遅れましたが、ブロック崩しが完成しました。
先日導入したSDLを使って効果音もつけれたので、形にはなったと思います。
ヘッダファイル
SEplayという関数プロトタイプを追加しました。
sedicisionという効果音管理のための変数を追加しました。
#ifndef BLOCK_H_
#define BLOCK_H_
void player();
int px = 320; // バーの基準x座標
int py = 430; // バーの基準y座標
int pmovex; // バーの移動値
int bx = 320; // ボールのx座標
int by = 414; // ボールのy座標
int l = 1; // x軸反射角変数の符号判定
int ll = -1; // y軸反射角変数の符号判定
int movex = 0; // ボールのx軸増減値
int movey = 0; // ボールのy軸増減値
int mylife = 2; // 自機の残機
int shoot = 0; // 打ち出す時の判定
int start = 0; // スタート判定
int gameover = 0; // ゲームオーバー判定
int clear = 0; // クリア判定
int leftm = 0; // 左移動の判定
int rightm = 0; // 右移動の判定
void allmove(); // 弾と自機の動き
Mix_Music *music;
Mix_Chunk *se1, *se2, *se3, *se4 ,*clearSE, *gameoverSE;
int channel1, channel2, channel3, channel4, channel5, channel6;
int sedecision = 0; // 反射音を交互に鳴らすための変数
void SEplay(); // 反射音を交互に鳴らすための関数
int cleari = 0;
int gameoveri = 0;
class Ball{
public:
int br ; // ボールの半径
int shotr; // ボールの移動角度
int shotdec; // 最初に発射する時に、spaceキーを押してるかの判定
bool setdec = true; // 数値の初期化ができるか判定
void set(); // 数値の入力
void ball(); // ボールの生成
void ballmove(); // ボールの動き
void reverse(); // ボールの当たり判定
void ReverseBar(); // バーの当たり判定
};
class Block{
public:
int blockx = 40; // ブロックの基準x座標
int blocky = 20; // ブロックの基準y座標
int spownx = 70; // 生成時のx軸差分
int spowny = 30; // 生成時のy軸差分
void block(int Num, int hNum); // ブロックの生成
void colorset(int Num); // ブロック生成時の色振り分け
void decision(int Num, int hNum); // 当たり判定
void decisiontest(int Num, int hNum); // 当たり判定テスト
};
int Life[5][10];
#endif
次に本コード
#include <GLUT/glut.h> // GLUTの有効化
#include <SDL2/SDL.h> // SDL2の有効化
#include <SDL2/SDL_mixer.h> // SDL mixerの有効化
#include "block.h" // ヘッダー
#include <cmath>
#include <iostream>
#include <cstdlib>
using namespace std;
#define WIDTH 640 // 画面の横サイズ
#define HEIGHT 480 // 画面の縦サイズ
#define PI 3.141592 // 円周率
void player(){ // バーの生成
glBegin(GL_POLYGON);
glColor3d(1.0, 1.0, 0.0);
glVertex2f(px + pmovex, py);
glVertex2f(px + 40 + pmovex, py - 5);
glVertex2f(px + 40 + pmovex, py + 5);
glVertex2f(px - 40 + pmovex, py + 5);
glVertex2f(px - 40 + pmovex, py - 5);
glVertex2f(px + 40 + pmovex, py - 5);
glEnd();
glBegin(GL_POLYGON);
glColor3d(0.0, 1.0, 1.0);
glVertex2f(px + 24 + pmovex, py - 5);
glVertex2f(px + 24 + pmovex, py + 5);
glVertex2f(px - 24 + pmovex, py + 5);
glVertex2f(px - 24 + pmovex, py - 5);
glEnd();
glBegin(GL_POLYGON);
glColor3d(1.0, 0.0, 1.0);
glVertex2f(px + 8 + pmovex, py - 5);
glVertex2f(px + 8 + pmovex, py + 5);
glVertex2f(px - 8 + pmovex, py + 5);
glVertex2f(px - 8 + pmovex, py - 5);
glEnd();
}
// テキスト表示
static void DrawString(string str, int w, int h, int x0, int y0){
glDisable(GL_LIGHTING);
// 平行投影にする
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// 画面上にテキスト描画
glRasterPos2f(x0, y0);
int size = (int)str.size();
for(int i = 0; i < size; ++i){
char ic = str[i];
// glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ic);
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, ic);
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
// ボールの生成
void Ball::ball(){
if(setdec){ set(); } // 一度だけ初期化
glBegin(GL_POLYGON);
//glColor3d(1.0, 0.0, 0.0);
glVertex2f(bx, by);
for(int i = 0; i < 360; ++i){
glVertex2f(bx + br * cos(i), by + br * sin(i));
}
glEnd();
}
void Ball::reverse(){
if(5 <= bx && bx <= 635 ){ // x軸(左右)の壁に当たった場合
/* 何もしない */
}else{
l = -1 * l; // x軸の増減値を反転させる
bx += l * movex;
by += ll * movey;
SEplay();
}
if(5 <= by && by <= 490){ // y軸(上)の壁に当たった場合
/* 何もしない */
}else{
ll = -1 * ll; // y軸の増減値を反転させる
bx += l * movex;
by += ll * movey;
SEplay();
}
// 自機(バー)の当たり判定
ReverseBar();
// ミスした時の挙動
if(by > 480){
mylife -= 1;
bx = px + pmovex;
by = py - 16;
movex = 0;
movey = 0;
shoot = 0;
ll = -1 * ll;
channel1 = Mix_PlayChannel(-1, se1, 0);
}
if(mylife < 0){ start = 2; gameover = 1; } // 終了
}
// 自機の当たり判定
void Ball::ReverseBar(){
if(px + pmovex - 40 < bx && bx < px + pmovex - 24 && py - 10 < by + 6 && by + 6 < py){
ll = -1 * ll; // y軸の増減値を反転させる
if(l == 1){
l = -1 * l;
}
movex = 4;
movey = 2;
bx += l * movex;
by += ll * movey;
SEplay();
}
if(px + pmovex - 23 < bx && bx < px + pmovex - 8 && py - 10 < by + 6 && by + 6 < py){
ll = -1 * ll; // y軸の増減値を反転させる
if(l == 1){
l = -1 * l;
}
movex = 2;
movey = 4;
bx += l * movex;
by += ll * movey;
SEplay();
}
if(px + pmovex - 7 < bx && bx < px + pmovex + 7 && py - 10 < by + 6 && by + 6 < py){
ll = -1 * ll; // y軸の増減値を反転させる
bx += l * movex;
by += ll * movey;
SEplay();
}
if(px + pmovex + 8 < bx && bx < px + pmovex + 23 && py - 10 < by + 6 && by + 6 < py){
ll = -1 * ll; // y軸の増減値を反転させる
if(l == -1){
l = -1 * l;
}
movex = 2;
movey = 4;
bx += l * movex;
by += ll * movey;
SEplay();
}
if(px + pmovex + 24 < bx && bx < px + pmovex + 40 && py - 10 < by + 6 && by + 6 < py){
ll = -1 * ll; // y軸の増減値を反転させる
if(l == -1){
l = -1 * l;
}
movex = 4;
movey = 2;
bx += l * movex;
by += ll * movey;
SEplay();
}
}
void Ball::set(){ // 初期化内容
br = 5; // ボールの半径
shotr = 45; // ボールの移動角度
shotdec = 0; // 最初に発射する時に、spaceキーを押してるかの判定
setdec = false;
}
void Block::decision(int Num, int hNum){ // ブロックの反射判定
// ブロック上の反射
if(blockx - 30 + (spownx * Num) < bx && bx < blockx + 30 + (spownx * Num) &&
blocky - 15 + (spowny * hNum) < by && by < blocky - 10 + (spowny * hNum)) {
if(Life[hNum][Num] == 0){ // 敵機に当たった時、弾の座標を戻す
ll = -1 * ll; // x軸の増減値を反転させる
Life[hNum][Num] = 1; // ブロックを消滅
clear += 1; // クリア判定の変数を加算
cout << clear << endl;
SEplay();
}
}
// ブロック下の反射
if(blockx - 30 + (spownx * Num) < bx && bx < blockx + 30 + (spownx * Num) &&
blocky + 10 + (spowny * hNum) < by && by < blocky + 15 + (spowny * hNum)) {
if(Life[hNum][Num] == 0){ // 敵機に当たった時、弾の座標を戻す
ll = -1 * ll; // x軸の増減値を反転させる
Life[hNum][Num] = 1; // ブロックを消滅
clear += 1; // クリア判定の変数を加算
cout << clear << endl;
SEplay();
}
}
// ブロック左の反射
if(blockx - 30 + (spownx * Num) < bx && bx < blockx - 25 + (spownx * Num) &&
blocky - 15 + (spowny * hNum) < by && by < blocky + 15 + (spowny * hNum)) {
if(Life[hNum][Num] == 0){ // 敵機に当たった時、弾の座標を戻す
l = -1 * l; // x軸の増減値を反転させる
Life[hNum][Num] = 1; // ブロックを消滅
clear += 1; // クリア判定の変数を加算
cout << clear << endl;
SEplay();
}
}
// ブロック右の反射
if(blockx + 25 + (spownx * Num) < bx && bx < blockx + 30 + (spownx * Num) &&
blocky - 15 + (spowny * hNum) < by && by < blocky + 15 + (spowny * hNum)) {
if(Life[hNum][Num] == 0){ // 敵機に当たった時、弾の座標を戻す
l = -1 * l; // x軸の増減値を反転させる
Life[hNum][Num] = 1; // ブロックを消滅
clear += 1; // クリア判定の変数を加算
cout << clear << endl;
SEplay();
}
}
}
// ブロックの生成
void Block::block(int Num, int hNum){
decision(Num, hNum);
if(Life[hNum][Num] == 0){
glBegin(GL_POLYGON);
colorset(hNum);
glVertex2f(blockx + (spownx * Num), blocky + (spowny * hNum));
glVertex2f(blockx + 30 + (spownx * Num), blocky - 10 + (spowny * hNum));
glVertex2f(blockx + 30 + (spownx * Num), blocky + 10 + (spowny * hNum));
glVertex2f(blockx - 30 + (spownx * Num), blocky + 10 + (spowny * hNum));
glVertex2f(blockx - 30 + (spownx * Num), blocky - 10 + (spowny * hNum));
glVertex2f(blockx + 30 + (spownx * Num), blocky - 10 + (spowny * hNum));
glEnd();
}
}
// ブロックの色判定
void Block::colorset(int Num){
(Num == 0 ? glColor3d(1.0, 0.0, 0.0) : Num == 1 ? glColor3d(1.0, 1.0, 0.0) : Num == 2
? glColor3d(0.0, 1.0, 0.0) : Num == 3 ? glColor3d(0.0, 0.0, 1.0) : Num == 4
? glColor3d(1.0, 0.0, 1.0) : glColor3d(1.0, 1.0, 1.0));
}
// 画面表示
void display(){
Ball b;
Block blo[5][10];
int i;
int j;
if(start == 0){ // スタート画面
glClear(GL_COLOR_BUFFER_BIT);
glColor3d(1.0, 1.0, 1.0);
DrawString("START", WIDTH, HEIGHT, 300, 240);
}
if(start == 1){
glClear(GL_COLOR_BUFFER_BIT);
player(); // 自機生成
b.ball(); // 弾の生成
for(i = 0; i <= 4; ++i){
for(j = 0; j <= 9; ++j){
blo[i][j].block(j, i); // ブロックの生成
glEnd();
}
}
}
if(gameover == 1){ // ゲームオーバー画面
glClear(GL_COLOR_BUFFER_BIT);
glColor3d(1.0, 0.0, 1.0);
DrawString("Game over", WIDTH, HEIGHT, 290, 240);
if(gameoveri == 0){
channel6 = Mix_PlayChannel(-1, gameoverSE, 0);
Mix_HaltMusic();
gameoveri = 1;
}
}
if(clear == 45){ // クリア画面
glClear(GL_COLOR_BUFFER_BIT);
glColor3d(1.0, 1.0, 0.0);
DrawString("Clear!", WIDTH, HEIGHT, 290, 240);
if(cleari == 0){
channel5 = Mix_PlayChannel(-1, clearSE, 1);
Mix_HaltMusic();
cleari = 1;
}
}
glFlush();
b.reverse(); // 壁と自機の当たり判定
}
void leftmove(){ // 自機左移動
if(px + pmovex > 40){ // 左端の当たり判定
pmovex -= 10.0;
}
if(shoot == 0){ bx = bx - 10; }; // スタート、もしくはミスした時の挙動
}
void rightmove(){ // 自機右移動
if(px + pmovex < 600){
pmovex += 10.0; // 右端の当たり判定
}
if(shoot == 0){ bx = bx + 10; }; // スタート、もしくはミスした時の挙動
}
void allmove(){
if(start ==1){
bx += l * movex; // x軸のボールの動き(仮)
by += ll * movey; // y軸のボールの動き(仮)
}
if(leftm == 1){
leftmove(); // 左移動
}
if(rightm == 1){
rightmove(); // 右移動
}
glutPostRedisplay();
}
// キーを押した時の
void keydowan(unsigned char key, int x, int y){
switch(key){
case 's':
case 'S':
if(start == 0){
start = 1; // 最初のスタート画面からゲーム画面に移行する
Mix_PlayMusic(music, -1);
}
break;
case 'g':
if(gameover == 1){ // ゲームオーバー画面に移行した時にウィンドウを閉じる
exit(1);
}
case 'a': // a を入力すると左に動く
case 'A':
leftm = 1; // 左移動の判定を出す
break;
case 'd': // d を入力すると右に動く
case 'D':
rightm = 1; // 右移動判定を出す
break;
case 'q': // q Q ESC を入力するとプログラム終了
case 'Q':
case '\033':
exit(0);
case ' ':
if(shoot == 0){
shoot = 1;
movex = 0;
movey = 4;
channel4 = Mix_PlayChannel(-1, se4, 0);
}
break;
case 'l':
//Mix_PlayChannel(-1, chunk, 0); // 効果再生
default:
break;
}
}
void keyup(unsigned char key, int x, int y){ // キーを離した時の挙動
switch(key){ // a A を離したときに移動を止める
case 'a':
case 'A':
leftm = 0;
break;
case 'd': // d D を話した時に移動を止める
case 'D':
rightm = 0;
break;
default: break;
}
}
void reshape(int w, int h){ // 座標の定義変更
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 640, 480, 0); // 左上を (0, 0) 右下を (640, 480)とする
}
void timer(int value){ // 毎秒ごとに再描画して、アニメーションさせる
glutIdleFunc(allmove); // 弾と自機の移動
glutTimerFunc(100, timer, 0); // 第一引数毎秒で繰り返す
}
void init(){
glClearColor(0.0, 0.0, 0.0, 1.0); // 背景色 黒
}
/*SDLの初期設定*/
void SDLsetup(){
if(0 != SDL_Init(SDL_INIT_AUDIO)){ // SDL初期化
cout << "SDL setup error" << endl;
exit(1);
}
Mix_AllocateChannels(16);
// SDL_Mixerオープン
if(0 != Mix_OpenAudio(22050, AUDIO_S16,2,4096)){
cout << "SDL mixer setup error" << endl;
exit(1);
}
/* ファイルから読み込む */
music = Mix_LoadMUS("loop_113.wav");
if(!music) { //ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
se1 = Mix_LoadWAV("se_sac01.wav");
if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
se2 = Mix_LoadWAV("se_sab04.wav");
if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
se3 = Mix_LoadWAV("se_sab05.wav");
if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
se4 = Mix_LoadWAV("se_mod05.wav");
if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
clearSE = Mix_LoadWAV("clear.wav");
if(!se1) { //ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
gameoverSE = Mix_LoadWAV("tin1.wav");
if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
cout << "failed to load music: " << Mix_GetError() << endl;
}
}
/*2つの反射音を交互に鳴らす関数*/
void SEplay(){
if(sedecision == 0){ // se判定の変数が0の時、効果音1を鳴らし、1を代入
channel2 = Mix_PlayChannel(-1, se2, 0);
sedecision = 1;
}else{ // se判定の変数が0の時、効果音2を鳴らし、0を代入
channel3 = Mix_PlayChannel(-1, se3, 0);
sedecision = 0;
}
}
int main(int argc, char *argv[]){
glutInitWindowPosition(100, 200); // ウィンドウ作成時の座標指定
glutInitWindowSize(WIDTH, HEIGHT); // ウィンドウサイズの指定
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA /*| GLUT_DOUBLE*/); // Red Green Brue +α(透明度)= RGBA
glutCreateWindow(argv[0]); // ウィンドウを生成。 argv[0]だとファイル名がそのままウィンドウ名になる
glutDisplayFunc(display); // display関数内を表示
glutKeyboardFunc(keydowan); // キーボードの入力挙動
glutKeyboardUpFunc(keyup); // 離した時の挙動
glutTimerFunc(100, timer, 0); // timer 関数内の実行
glutReshapeFunc(reshape); // 画面の再定義
init();
SDLsetup();
glutMainLoop();
return 0;
}
part1のコードに効果音と簡単なスタート画面、クリア画面、ゲームオーバー画面を付け加えたものです。音源ファイルはwav形式のものを使ってください。
開発環境
Mac version 10.10.5
ターミナルコマンド
g++ -o ファイル名.out ファイル名.cpp -mmacosx-version-min=10.8 -framework GLUT -framework OpenGL -lSDL2 -lSDL2_mixer
これからは3D処理のプログラムも触っていくと思うので、改めて計算方法を見直したいと思います。