シューティングゲームの原型。 弾の発射、当たり判定まで!
当たり判定の計算のため、座標の考え方が変わっています。
# 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(); // 5つループで生成するため、中に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;
}
シューティングの原型はとりあえず、ここまでです!