InvaderGame ver1.00

#概要
OpenGL/GLUTにて作成したインベーダーゲームです。
敵の数は８匹、ランダムに発射してくる弾を避けつつ、敵を倒します。
![スクリーンショット 2016-06-20 12.31.31.png](https://qiita-image-store.s3.amazonaws.com/0/121172/1e13a2f3-edd6-837b-9ab8-205fb7d9860f.png)
#環境
Mac OS X 10.10.1 GNU gcc使用
######コンパイルコマンド
~~~
g++ -o InvaderGame.o main.cpp invaderClass.cpp unitClass.cpp -mmacosx-version-min=10.8 -framework GLUT -framework OpenGL
~~~
#プログラムファイル
###invaderClass.h
~~~
#ifndef _INVADER_CLASS
#define _INVADER_CLASS

#include <GLUT/glut.h>
#include <cmath>
using namespace std;

#define DRAW_MAG 		4		//描画時倍率
#define INVADER_SPEED	0.1		//インベーダーの移動速度
#define MOVE_COUNT		400		//インベーダーの折り返しカウント
#define PI 				3.141592//π
#define HEIGHT			480		//画面縦幅
#define SHOT_X			20		//弾発射位置を真ん中に調整

class INVADER{
public:
	INVADER(int x, int y);				//constructor
	void InvaderPoint(int x, int y);	//描画
	void Coordinate();					//座標
	void Magnification();				//倍率変更
	void Initialization();				//初期化
	void Move();						//動き
	bool Shot(int y);					//攻撃
	void Dead();						//死亡
	int DrawyReturn();					//弾発射時用drawy渡し
	int ShotxReturn();					//当たり判定時shotx渡し
	bool Hit(int uShotx, int uShoty);	//当たり判定
private:
	bool life;			//生死判定
	double invx,invy;	//bool invaderの座標取得ループの値保存用
	double drawx, drawy;//描画位置
	int shotx; 			//弾発射時のx座標保存
	int mcount; 		//移動距離記憶
	bool move; 			//移動方向記憶
	const bool invader[10][10] = {
	// y 0 1 2 3 4 5 6 7 8 9     x
		{0,0,0,0,0,1,1,1,0,0,},//0
		{0,0,0,0,1,1,0,0,0,0,},//1
		{0,1,0,1,1,1,1,1,0,0,},//2
		{0,0,1,1,0,1,1,0,1,0,},//3
		{0,0,0,1,1,1,1,0,0,0,},//4
		{0,0,0,1,1,1,1,0,0,0,},//5
		{0,0,1,1,0,1,1,0,1,0,},//6
		{0,1,0,1,1,1,1,1,0,0,},//7
		{0,0,0,0,1,1,0,0,0,0,},//8
		{0,0,0,0,0,1,1,1,0,0,},//9
		};
};

#endif
~~~
###invaderClass.cpp
~~~
#include "invaderClass.h"
#include <GLUT/glut.h>
#include <cmath>
#include <iostream>
using namespace std;

INVADER::INVADER(int x, int y){
	life = true;
	drawx = x; drawy = y;//初期位置設定
	move = true;
	Initialization();
}

//DRAW_MAG pix ずつ QUADS 作成し描画
void INVADER::InvaderPoint(int x, int y){
	glColor3d(1.0,0.0,0.0); //赤色
	glBegin(GL_QUADS);
	glVertex2i(x  ,y);
	glVertex2i(x  ,y+DRAW_MAG);
	glVertex2i(x+DRAW_MAG,y+DRAW_MAG);
	glVertex2i(x+DRAW_MAG,y);
	glEnd();
}

//描画座標の決定
void INVADER::Coordinate(){
	int x = invx + drawx,
		y = invy + drawy;
	InvaderPoint(x, y);
}


//倍率変更
void INVADER::Magnification(){
	invx = invx * DRAW_MAG;
	invy = invy * DRAW_MAG;
	Coordinate();
}

//初期化。配列情報取得ループ
void INVADER::Initialization(){
	for(int x = 0; x < 10; x++){
		for(int y = 0; y < 10; y++){
			if(invader[x][y] == true){
				invx = x; invy = y;
				Magnification();
			}
		}
	}
}

//移動
void INVADER::Move(){
	if(life){
		if(move == true){
			drawx -= INVADER_SPEED;//Left
		}else if(move == false){
			drawx += INVADER_SPEED;//Right
		}

		//壁に当たったら一段下がって折り返しの動きをさせる
		mcount++;
		if(mcount > MOVE_COUNT){
			drawy += 10;//Dawn
			mcount = 0;
			move = move ? false : true;
		}
		Initialization();
	}
}

//弾発射
bool INVADER::Shot(int y){
	if(life){
		//x座標の初期設定
		if(y == drawy){
			shotx = drawx;
		}
		glColor3d(1.0,1.0,1.0);
		glPointSize(5);
		glBegin(GL_POINTS);
		glVertex2d(shotx+SHOT_X,y + 40);
		glEnd();

		//弾描画終了判定
		if(y > HEIGHT){
			return false;
		}else return true;
	}
}

//死亡
void INVADER::Dead(){
	life = false;
}

//drawyを渡すだけ
int INVADER::DrawyReturn(){
	return drawy;
}

//shotxを渡すだけ
int INVADER::ShotxReturn(){
	return shotx;
}

//当たり判定部
bool INVADER::Hit(int uShotx, int uShoty){
	if(life){
		double x , y, 
			   maxx = drawx, minx = drawx,
			   maxy = drawy, miny = drawy;

		//円描画
		for(double i = -20.0; i < 20.0; i++){
			y = 20 * sin((i + 180) / PI);
			x = 20 * cos((i + 180) / PI);
			//Invaderの座標を適用
			y += drawy + 20.0;
			x += drawx + 20.0;
			//x,yの最大、最小値を記憶
			if(drawx + 20.0 < x && maxx < x)maxx = x;
			if(drawx + 20.0 > x && minx > x)minx = x;
			if(drawy + 20.0 < y && maxy < y)maxy = y;
			if(drawy + 20.0 > y && miny > y)miny = y;

			//x,yの範囲内に弾の座標が入れば死亡
			//当たり判定は矩形になる
			if(uShotx > minx && uShotx < maxx && uShoty > miny && uShoty < maxy){
				Dead();
				return true;
			}
			return false;
		}
	}
}
~~~
###unitClass.h
~~~
#ifndef _UNIT_CLASS
#define _UNIT_CLASS
#include <GLUT/glut.h>
#include <cmath>

#define UNIT_X 			300		//ユニット初期位置ｘ軸
#define UNIT_Y 			400		//ユニット初期位置Y軸
#define DRAW_MAG 		4		//描画時倍率
#define WIDTH 			640		//画面横幅
#define PI 				3.141592//π
#define SHOT_X			20		//弾発射位置を真ん中に調整

class UNIT{
public:
	UNIT();
	void Drawing(int x, int y);			//描画
	void Coordinate();					//座標決定
	void Magnification();				//倍率変更
	void Initialization();				//初期化
	int Shot(int y);					//弾発射
	void LeftMove();					//左移動
	void RightMove();					//右移動
	void Dead();						//死亡
	void Hit(int iShotx, int iShoty);	//当たり判定
private:
	int unitx,unity;//bool arrayの座標取得ループの値保存用
	int drawx,drawy;//描画位置
	bool life;		//生死判定
	//[x][y]
	bool unit[10][10] = {
	// y 0 1 2 3 4 5 6 7 8 9	 x
		{0,0,0,0,0,1,1,1,1,0,},//0
		{0,0,0,0,0,1,1,1,1,0,},//1
		{0,0,0,0,0,1,1,1,1,0,},//2
		{0,0,1,1,1,1,1,1,1,0,},//3
		{0,0,1,1,1,1,1,1,1,0,},//4
		{0,0,1,1,1,1,1,1,1,0,},//5
		{0,0,1,1,1,1,1,1,1,0,},//6
		{0,0,0,0,0,1,1,1,1,0,},//7
		{0,0,0,0,0,1,1,1,1,0,},//8
		{0,0,0,0,0,1,1,1,1,0,},//9
	};
};

#endif
~~~
###unitClass.cpp
~~~
#include "unitClass.h"
#include <GLUT/glut.h>
#include <cmath>

UNIT::UNIT(){
	drawx = UNIT_X;
	drawy = UNIT_Y;
	life = true;
}

//DRAW_MAG pix ずつ QUADS 作成し描画
void UNIT::Drawing(int x, int y){
	glColor3d(1.0,1.0,1.0);
	glBegin(GL_QUADS);
	glVertex2i(x  ,y);
	glVertex2i(x  ,y+DRAW_MAG);
	glVertex2i(x+DRAW_MAG,y+DRAW_MAG);
	glVertex2i(x+DRAW_MAG,y);
	glEnd();
}



//描画座標の決定
void UNIT::Coordinate(){
	int x = unitx + drawx,
		y = unity + drawy;
		Drawing(x, y);
}

//倍率変更
void UNIT::Magnification(){
	unitx = unitx * DRAW_MAG;
	unity = unity * DRAW_MAG;
	Coordinate();
}

//初期化。配列情報取得ループ
void UNIT::Initialization(){
	if(life){
		for(int x = 0; x < 10; x++){
			for(int y = 0; y < 10; y++){
				if(unit[x][y] == true){
					unitx = x; unity = y;
					Magnification();
				}
			}
		}
	}
}

//左移動
void UNIT::LeftMove(){
	drawx -= 4;
	if(drawx < 0)drawx = 0;
	Initialization();
}

//右移動
void UNIT::RightMove(){
	drawx += 4;
	if(drawx > WIDTH - DRAW_MAG * 10)drawx = WIDTH - DRAW_MAG * 10;
	Initialization();
}

//死亡
void UNIT::Dead(){
	life = false;
}

//弾発射
int UNIT::Shot(int y){
	if(life){
		static int x = 0;
		//x座標の初期設定
		if(y == UNIT_Y){
			x = drawx;
		}
		glColor3d(1.0,1.0,1.0);
		glPointSize(4);
		glBegin(GL_POINTS);
		glVertex2d(x+SHOT_X,y);
		glEnd();
		//戻り値をUnit描画の中心に調整
		return x + SHOT_X;
	}
}

//当たり判定
void UNIT::Hit(int iShotx, int iShoty){
	double x , y,
		   maxx = drawx, minx = drawx,
		   maxy = drawy, miny = drawy;

	//円描画
	for(double i = -20.0; i < 20.0; i++){
		y = 20 * sin((i + 180) / PI);
		x = 20 * cos((i + 180) / PI);
		//Unitの座標を適用
		y += drawy + 20.0;
		x += drawx + 20.0;
		//x,yの最大、最小値を記憶
		if(drawx + 20.0 < x && maxx < x)maxx = x;
		if(drawx + 20.0 > x && minx > x)minx = x;
		if(drawy + 20.0 < y && maxy < y)maxy = y;
		if(drawy + 20.0 > y && miny > y)miny = y;
		
		//x,yの範囲内に弾の座標が入れば死亡
		if(iShotx > minx && iShotx < maxx && iShoty + 40 > miny && iShoty + 40 < maxy){
			Dead();
		}
		
	}
}
~~~
###main.cpp
~~~
#include "invaderClass.h"
#include "unitClass.h"
#include <GLUT/glut.h>
#include <cstdlib>
#include <ctime>

#define WIDTH 			640		//画面横幅
#define HEIGHT			480		//画面縦幅
#define INVADER_Y 		40		//インベーダー初期位置Y軸

//UNIT弾発射判定
GLboolean unitBulletParameter = GL_FALSE;
UNIT unit;
int unitMove = 0;

void display(){
	glClear(GL_COLOR_BUFFER_BIT);
	static INVADER inv0( 40, INVADER_Y), inv1(120, INVADER_Y), inv2(200, INVADER_Y), inv3(280, INVADER_Y),
				   inv4(360, INVADER_Y), inv5(440, INVADER_Y), inv6(520, INVADER_Y), inv7(600, INVADER_Y);
	
	//弾発射判定用
	static bool inv0b = false, inv1b = false, inv2b = false, inv3b = false,
				inv4b = false, inv5b = false, inv6b = false, inv7b = false;

	//Invader描画
	inv0.Move();inv1.Move();inv2.Move();inv3.Move();
	inv4.Move();inv5.Move();inv6.Move();inv7.Move();

	//Unit描画
	unit.Initialization();

	//unit射撃のための条件式
	if(unitBulletParameter == GL_TRUE){
		static int i = UNIT_Y;	//弾のy座標
		int x;				//弾のx座標
		x = unit.Shot(i);
		i -= 8;
		if(i < 0){
			i = UNIT_Y;
			unitBulletParameter = GL_FALSE;
		}
		//それぞれの当たり判定に重なるかチェック。重なれば弾は消える。
		if(inv0.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv1.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv2.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv3.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv4.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv5.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv6.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
		if(inv7.Hit(x,i)){unitBulletParameter = GL_FALSE; i = UNIT_Y;}
	}

	//敵弾発射ランダム
	switch(rand() % 400){
		case 0:
			inv0b = true;
			break;
		case 1:
			inv1b = true;
			break;
		case 2:
			inv2b = true;
			break;
		case 3:
			inv3b = true;
			break;
		case 4:
			inv4b = true;
			break;
		case 5:
			inv5b = true;
			break;
		case 6:
			inv6b = true;
			break;
		case 7:
			inv7b = true;
			break;
	}

	//敵の弾発射部分
	if(inv0b){
		bool foo = false;
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv0.DrawyReturn();
		}
		inv0b = inv0.Shot(i);
		i += 4;
		x = inv0.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv1b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv1.DrawyReturn();
		}
		inv1b = inv1.Shot(i);
		i += 4;
		x = inv1.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv2b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv2.DrawyReturn();
		}
		inv2b = inv2.Shot(i);
		i += 4;
		x = inv2.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv3b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv3.DrawyReturn();
		}
		inv3b = inv3.Shot(i);
		i += 4;
		x = inv3.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv4b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv4.DrawyReturn();
		}
		inv4b = inv4.Shot(i);
		i += 4;
		x = inv4.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv5b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv5.DrawyReturn();
		}
		inv5b = inv5.Shot(i);
		i += 4;
		x = inv5.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv6b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv6.DrawyReturn();
		}
		inv6b = inv6.Shot(i);
		i += 4;
		x = inv6.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	if(inv7b){
		int x;
		static int i = 0;
		if(i >= HEIGHT){
			i = inv7.DrawyReturn();
		}
		inv7b = inv7.Shot(i);
		i += 4;
		x = inv7.ShotxReturn();
		unit.Hit(x+SHOT_X, i);
	}

	glutSwapBuffers();
}

void UnitMove(){
	if(unitMove == 1)unit.LeftMove();
	else if(unitMove == 2)unit.RightMove();
	glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y){
	switch(key){
		case ' ':
			unitBulletParameter = GL_TRUE;
			glutPostRedisplay();
			break;
		case 'a':
		case 'A':
			unitMove = 1;
			break;
		case 'd':
		case 'D':
			unitMove = 2;
			break;
		case 'q':
		case 'Q':
		case '\033':
			exit(0);
	}
}

void keyboardup(unsigned char key, int x, int y){
	switch(key){
		case 'a':
		case 'A':
			unitMove = 0;
			break;
		case 'd':
		case 'D':
			unitMove = 0;
			break;
	}
}

void specialKey(int key, int x, int y){
	switch(key){
		case GLUT_KEY_LEFT:
			unitMove = 1;
			break;
		case GLUT_KEY_RIGHT:
			unitMove = 2;
			break;
	}
}

void specialUpKey(int key, int x, int y){
	switch(key){
		case GLUT_KEY_LEFT:
			unitMove = 0;
			break;
		case GLUT_KEY_RIGHT:
			unitMove = 0;
			break;
	}
}

void timer(int value){
	glutIdleFunc(UnitMove);
	glutTimerFunc(50,timer,0);
}

void Init(){
	glClearColor(0.0,0.0,0.0,0.0);
	glOrtho(0,WIDTH,HEIGHT,0,-1,1);
}

void resize(int w, int h){
	glViewport(0,0,w,h);
	glLoadIdentity();
	glOrtho(0,WIDTH,HEIGHT,0,-1,1);
}

int main(int argc, char *argv[]){
	srand((unsigned int)time(NULL));
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutInitWindowSize(WIDTH,HEIGHT);
	glutCreateWindow("Invader");
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutKeyboardUpFunc(keyboardup);
	glutSpecialFunc(specialKey);
	glutSpecialUpFunc(specialUpKey);
	glutIgnoreKeyRepeat(GL_TRUE);	 //キーの繰り返し入力を無視
	glutReshapeFunc(resize);
	glutTimerFunc(100,timer,0);
	Init();
	glutMainLoop();
	return 0;
}
~~~
---
今後修正したい部分として
1.クラスの配列化
2.if文の統一
等をし、コードを簡略化しつつ、
1.スタート画面、終了画面の実装
2.BGM、SEの実装
等を行いたいと考えてます。