LoginSignup
5
7

More than 5 years have passed since last update.

shooting OpenGL 02 / 02 Hit

Last updated at Posted at 2015-07-15

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

#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;
}

スクリーンショット 2015-07-15 19.05.44.png

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

5
7
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
5
7