ブロック崩し part2 (完)

遅れましたが、ブロック崩しが完成しました。
先日導入した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;
    }
  
}

/*２つの反射音を交互に鳴らす関数*/
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処理のプログラムも触っていくと思うので、改めて計算方法を見直したいと思います。