2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

InvaderGame ver1.00

Posted at

概要

OpenGL/GLUTにて作成したインベーダーゲームです。
敵の数は8匹、ランダムに発射してくる弾を避けつつ、敵を倒します。
スクリーンショット 2016-06-20 12.31.31.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		//ユニット初期位置x軸
# 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の実装
等を行いたいと考えてます。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?