shooting OpenGL 02 / 02 Hit

シューティングゲームの原型。　弾の発射、当たり判定まで！
当たり判定の計算のため、座標の考え方が変わっています。

```
#include <GLUT/glut.h>
#include <cmath>
#include <iostream>
#include <cstdlib>
using namespace std;
#define WIDTH 640
#define HEIGHT 480
#define PI 3.141592

class Enemy{
public:
	float enemyr; //enemyの半径
	float x;  // x座標
	float y;  // y座標
	
	void genel(int Num);	// 円生成
	void judge(int Num);	// 当たり判定
	Enemy();				// 初期化コストラクタ
};
	/////////////////////////////////////////////////////////////////////////
	void player();		// 自機生成
	float movex = 0.0;	// 自機のx軸移動値
	float mx = 320.0;	// 自機のx軸移動値 						// 自機変数
	float my = 430.0;	// 自機のy軸
	float mh = (sqrt(3) / 2) * 60;	// 自機の三角の頂点
	/////////////////////////////////////////////////////////////////////////
	float Emovex = 0.0;		// 敵機のx軸移動値
	int l = 1;				// 円を動かす変数の符号を判断する		// 敵機変数
	int Life[5];
	/////////////////////////////////////////////////////////////////////////
	float smovey = 0.0;		// 弾のy軸移動値
	float smovex = 0.0; 	// 弾のx軸移動値
	float shootx = 320.0;		// 弾のx座標 						// 弾変数
	float shooty = 430.0;		// 弾のy座標
	float shootr = 5.0;			// 弾の半径
	//////////////////////////////////////////////////////////////////////////


Enemy::Enemy(){		// 円の半径
	enemyr = 30.0;
}


void Enemy::genel(int Num){		// 敵機生成
	x  =  80.0 + 120.0 * Num;	// 敵機x座標の定義 クラス配列を使うため、加算させる
	y  =  80.0;					// 敵機y座標の定義
	judge(Num);					// 敵機を表示させるかさせないかの判定
	if(Life[Num] == 0){			// 敵機の表示変数がtrue (0) の場合表示
		glColor3d(1.0, 1.0, 0.0);	// 色指定
		glBegin(GL_POLYGON);
		glVertex2f(x + Emovex, y);	// 基準座標指定
		for(int i = 0; i < 360; ++i){
			glVertex2f(x + enemyr * cos(i) + Emovex, y + enemyr * sin(i)); // 円の周りの生成
		}
	}
}

void shoottest(){	// 弾の生成
	Enemy e;	// Enemyクラスのオブジェクト化
	glBegin(GL_POLYGON);
	glColor3d(1.0,0.0,0.0);	// 色指定
	glVertex2f(shootx + smovex, shooty + smovey);	// 基準座標指定
	for(int i = 0; i < 360; ++i){
		glVertex2f(shootx + smovex + shootr * cos(i) , shooty + smovey + shootr * sin(i)); // 周り生成
	}
	glEnd();
	if(-430.0 < smovey && smovey < 0.0){	// 弾が発射されてる場合、画面外にでるまで座標移動
		smovey -= 30.0;
	}else{
		smovey = 0.0;						// 範囲外にでたらx座標とy座標の初期化
		smovex = movex;
	}
}

void Enemy::judge(int Num){ // 当たり判定
	if((enemyr + shootr) <= sqrt(((x + Emovex) - (shootx + smovex)) *  ((x + Emovex) - (shootx + smovex))
					 + (y - (shooty + smovey)) * (y - (shooty + smovey)))  ){
		/*何もしない */
	}else if(Life[Num] != 1){	// 敵機に当たった時、弾の座標を戻す
		smovey = 0.0;
		smovex = movex;
		Life[Num] = 1;
	}else{						// 当たり判定を出したあと、通りすぎるようにするため =1 にする
		Life[Num] = 1;
	}
} 


void player(){		// 自機の生成
	glBegin(GL_POLYGON);		// 三角(自機)の生成
	glColor3d(2.0, 4.0, .0);	// 自機の色(黄色)
	glVertex2f(mx + movex, my);
	glVertex2f((mx + 30) + movex, my + (mh / 2));
	glVertex2f((mx - 30) + movex, my + (mh / 2));
	glVertex2f(mx + movex, my - (mh / 2));
	glVertex2f((mx + 30) + movex, my + (mh / 2));

	glEnd();
}



void display(){
	Enemy e[5];	// Enemyクラスを配列でオブジェクト化

	glClear(GL_COLOR_BUFFER_BIT);
	for(int i = 0; i < 5; ++i){
		e[i].genel(i);			// 敵機の作成
		glEnd();				// ５つループで生成するため、中にglEndを入れる
	}

	shoottest();				// 弾の生成
	player();					// 自機の生成

	glutSwapBuffers();		// ダブルバッファリングの関数

}

void leftmove(){	// 自機左移動
	if(mx + movex > 30){	// 左端の当たり判定
			movex -= 10.0;		
			if(smovey == 430.0){ smovex -= 50.0; }	// 弾の左移動
			glutPostRedisplay();
		}
}

void rightmove(){	// 自機右移動
	if(mx + movex < 610){
			movex += 10.0;		// 右端の当たり判定
			if(smovey == 430.0){ smovex += 50.0; }	// 弾の右移動
			glutPostRedisplay();
	}
}

void keyup(unsigned char key, int x, int y){	// キーを話した時の挙動
	switch(key){	// a A を離したときに移動を止める
		case 'a':
		case 'A': 
		glutIdleFunc(0);
		break;

		case 'd':	// d D を話した時に移動を止める
		case 'D':
		glutIdleFunc(0);
		break;

		default: break;

	}	
}

void keyboard(unsigned char key, int x, int y){

	switch(key){
		case 'a':	// a を入力すると左に動く
		case 'A': 

		glutIdleFunc(leftmove);
		break;

		case 'd':	// d を入力すると右に動く
		case 'D':

		glutIdleFunc(rightmove);
		break;

		case ' ':	// 弾発射
		smovey -= 50.0;

		break;
			
		case 'q':	// q Q ESC を入力するとプログラム終了
		case 'Q':
		case '\033':
		exit(0);

		default: 
		break;
	}
}


void timer(int value){	// 毎秒ごとに再描画して、アニメーションさせる
	if(-50.0 < Emovex && Emovex < 80){	// 範囲内の時に動かす
		Emovex += l * 5.0;
	}else{
		l = -1 * l;						// 範囲外にきたら符号を逆転させる
		Emovex += l * 5.0;
	}
	
	glutPostRedisplay();				// 再描画
	glutTimerFunc(40, timer, 0);		// 第一引数毎秒で繰り返す
}

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 init(){
	glClearColor(0.0, 0.0, 0.0, 1.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(keyboard);			// キーボードの入力挙動
	glutKeyboardUpFunc(keyup);			// 離した時の挙動
	glutTimerFunc(100, timer, 0);		// timer 関数内の実行
	glutReshapeFunc(reshape);			// 画面の再定義
	init();
	glutMainLoop();
	return 0;
}
```

![スクリーンショット 2015-07-15 19.05.44.png](https://qiita-image-store.s3.amazonaws.com/0/85547/71462646-8db6-99cc-e156-a8d167edf08b.png "スクリーンショット 2015-07-15 19.05.44.png")

シューティングの原型はとりあえず、ここまでです！