LoginSignup
4
2

More than 5 years have passed since last update.

ブロック崩し part2 (完)

Last updated at Posted at 2015-08-29

遅れましたが、ブロック崩しが完成しました。
先日導入したSDLを使って効果音もつけれたので、形にはなったと思います。

ヘッダファイル
SEplayという関数プロトタイプを追加しました。
sedicisionという効果音管理のための変数を追加しました。

#ifndef BLOCK_H_
#define BLOCK_H_

    void player();

    int px = 320; // バーの基準x座標
    int py = 430; // バーの基準y座標
    int pmovex;   // バーの移動値



    int bx = 320;   // ボールのx座標
    int by = 414;   // ボールのy座標
    int l  = 1;     // x軸反射角変数の符号判定
    int ll = -1;    // y軸反射角変数の符号判定
    int movex = 0;  // ボールのx軸増減値
    int movey = 0;  // ボールのy軸増減値
    int mylife = 2; // 自機の残機
    int shoot = 0;      // 打ち出す時の判定

    int start = 0;      // スタート判定
    int gameover = 0;   // ゲームオーバー判定
    int clear = 0;      // クリア判定

    int leftm = 0;      // 左移動の判定
    int rightm = 0;     // 右移動の判定
    void allmove();     // 弾と自機の動き

    Mix_Music *music;
    Mix_Chunk *se1, *se2, *se3, *se4 ,*clearSE, *gameoverSE;
    int channel1, channel2, channel3, channel4, channel5, channel6;

    int sedecision = 0; // 反射音を交互に鳴らすための変数
    void SEplay();      // 反射音を交互に鳴らすための関数

    int cleari = 0;
    int gameoveri = 0;

class Ball{
public:

    int br ; // ボールの半径
    int shotr; // ボールの移動角度
    int shotdec; // 最初に発射する時に、spaceキーを押してるかの判定


    bool setdec = true; // 数値の初期化ができるか判定

    void set();         // 数値の入力
    void ball();        // ボールの生成
    void ballmove();    // ボールの動き
    void reverse();     // ボールの当たり判定

    void ReverseBar();  // バーの当たり判定
};

class Block{
public:
    int blockx = 40;        // ブロックの基準x座標
    int blocky = 20;        // ブロックの基準y座標

    int spownx = 70;        // 生成時のx軸差分
    int spowny = 30;        // 生成時のy軸差分



    void block(int Num, int hNum);          // ブロックの生成
    void colorset(int Num);                 // ブロック生成時の色振り分け
    void decision(int Num, int hNum);       // 当たり判定
    void decisiontest(int Num, int hNum);   // 当たり判定テスト
};
    int Life[5][10]; 

#endif 

次に本コード

#include <GLUT/glut.h>  // GLUTの有効化
#include <SDL2/SDL.h>   // SDL2の有効化
#include <SDL2/SDL_mixer.h>     // SDL mixerの有効化
#include "block.h"      // ヘッダー
#include <cmath>
#include <iostream>
#include <cstdlib>
using namespace std;
#define WIDTH 640   // 画面の横サイズ
#define HEIGHT 480  // 画面の縦サイズ
#define PI 3.141592     // 円周率



void player(){  // バーの生成
    glBegin(GL_POLYGON);
    glColor3d(1.0, 1.0, 0.0);
    glVertex2f(px + pmovex, py);
    glVertex2f(px + 40 + pmovex, py - 5);
    glVertex2f(px + 40 + pmovex, py + 5);
    glVertex2f(px - 40 + pmovex, py + 5);
    glVertex2f(px - 40 + pmovex, py - 5);
    glVertex2f(px + 40 + pmovex, py - 5);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3d(0.0, 1.0, 1.0);
    glVertex2f(px + 24 + pmovex, py - 5);
    glVertex2f(px + 24 + pmovex, py + 5);
    glVertex2f(px - 24 + pmovex, py + 5);
    glVertex2f(px - 24 + pmovex, py - 5);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3d(1.0, 0.0, 1.0);
    glVertex2f(px + 8 + pmovex, py - 5);
    glVertex2f(px + 8 + pmovex, py + 5);
    glVertex2f(px - 8 + pmovex, py + 5);
    glVertex2f(px - 8 + pmovex, py - 5);
    glEnd();
}

// テキスト表示
static void DrawString(string str, int w, int h, int x0, int y0){
    glDisable(GL_LIGHTING);
    // 平行投影にする
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(0, w, h, 0);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    // 画面上にテキスト描画
    glRasterPos2f(x0, y0);
    int size = (int)str.size();
    for(int i = 0; i < size; ++i){
        char ic = str[i];
       // glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ic);
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, ic);
    }

    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
}

// ボールの生成
void Ball::ball(){ 
    if(setdec){ set(); }    // 一度だけ初期化
    glBegin(GL_POLYGON);
    //glColor3d(1.0, 0.0, 0.0);
    glVertex2f(bx, by);
    for(int i = 0; i < 360; ++i){
        glVertex2f(bx + br * cos(i), by + br * sin(i));
    }
    glEnd();
}

void Ball::reverse(){
    if(5 <= bx && bx <= 635 ){  // x軸(左右)の壁に当たった場合
        /* 何もしない */
    }else{
        l = -1 * l;     // x軸の増減値を反転させる
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }

    if(5 <= by && by <= 490){   // y軸(上)の壁に当たった場合
        /* 何もしない */
    }else{
        ll = -1 * ll;   // y軸の増減値を反転させる
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }

    // 自機(バー)の当たり判定
    ReverseBar();

    // ミスした時の挙動
    if(by > 480){ 
        mylife -= 1;
        bx = px + pmovex;
        by = py - 16;
        movex = 0;
        movey = 0;
        shoot = 0;
        ll = -1 * ll;
        channel1 = Mix_PlayChannel(-1, se1, 0);
    }
    if(mylife < 0){ start = 2; gameover = 1; }  // 終了
}

// 自機の当たり判定
void Ball::ReverseBar(){
    if(px + pmovex - 40 < bx && bx < px + pmovex - 24 && py - 10 < by + 6 && by + 6 < py){ 
        ll = -1 * ll;   // y軸の増減値を反転させる
        if(l == 1){
            l = -1 * l;
        }
        movex = 4;
        movey = 2;
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }
    if(px + pmovex - 23 < bx && bx < px + pmovex - 8 && py - 10 < by + 6 && by + 6 < py){ 
        ll = -1 * ll;   // y軸の増減値を反転させる
        if(l == 1){
            l = -1 * l;
        }
        movex = 2;
        movey = 4;
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }
    if(px + pmovex - 7 < bx && bx < px + pmovex + 7 && py - 10 < by + 6 && by + 6 < py){ 
        ll = -1 * ll;   // y軸の増減値を反転させる
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }
    if(px + pmovex + 8 < bx && bx < px + pmovex + 23 && py - 10 < by + 6 && by + 6 < py){ 
        ll = -1 * ll;   // y軸の増減値を反転させる
        if(l == -1){
            l = -1 * l;
        }
        movex = 2;
        movey = 4;
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }
    if(px + pmovex + 24 < bx && bx < px + pmovex + 40 && py - 10 < by + 6 && by + 6 < py){ 
        ll = -1 * ll;   // y軸の増減値を反転させる
        if(l == -1){
            l = -1 * l;
        }
        movex = 4;
        movey = 2;
        bx += l  * movex;
        by += ll * movey;
        SEplay();
    }
}


void Ball::set(){   // 初期化内容
    br = 5;         // ボールの半径
    shotr = 45;     // ボールの移動角度
    shotdec = 0;    // 最初に発射する時に、spaceキーを押してるかの判定

    setdec = false;
}

void Block::decision(int Num, int hNum){    // ブロックの反射判定

    // ブロック上の反射
    if(blockx - 30 + (spownx * Num)  < bx && bx < blockx + 30 + (spownx * Num) &&
       blocky - 15 + (spowny * hNum) < by && by < blocky - 10 + (spowny * hNum)) {

        if(Life[hNum][Num] == 0){       // 敵機に当たった時、弾の座標を戻す
                ll = -1 * ll;           // x軸の増減値を反転させる
                Life[hNum][Num] = 1;    // ブロックを消滅
                clear += 1;             // クリア判定の変数を加算
                cout << clear << endl;
                SEplay();
        }           
    }

    // ブロック下の反射
    if(blockx - 30 + (spownx * Num)  < bx && bx < blockx + 30 + (spownx * Num) &&
       blocky + 10 + (spowny * hNum) < by && by < blocky + 15 + (spowny * hNum)) {

        if(Life[hNum][Num] == 0){       // 敵機に当たった時、弾の座標を戻す
                ll = -1 * ll;           // x軸の増減値を反転させる
                Life[hNum][Num] = 1;    // ブロックを消滅
                clear += 1;             // クリア判定の変数を加算
                cout << clear << endl;
                SEplay();
        }           
    }

    // ブロック左の反射
    if(blockx - 30 + (spownx * Num)  < bx && bx < blockx - 25 + (spownx * Num) &&
       blocky - 15 + (spowny * hNum) < by && by < blocky + 15 + (spowny * hNum)) {

        if(Life[hNum][Num] == 0){       // 敵機に当たった時、弾の座標を戻す
                l = -1 * l;             // x軸の増減値を反転させる
                Life[hNum][Num] = 1;    // ブロックを消滅
                clear += 1;             // クリア判定の変数を加算
                cout << clear << endl;
                SEplay();
        }           
    }

    // ブロック右の反射
    if(blockx + 25 + (spownx * Num)  < bx && bx < blockx + 30 + (spownx * Num) &&
       blocky - 15 + (spowny * hNum) < by && by < blocky + 15 + (spowny * hNum)) {

        if(Life[hNum][Num] == 0){       // 敵機に当たった時、弾の座標を戻す
                l = -1 * l;             // x軸の増減値を反転させる
                Life[hNum][Num] = 1;    // ブロックを消滅
                clear += 1;             // クリア判定の変数を加算
                cout << clear << endl;
                SEplay();
        }           
    }
}

// ブロックの生成
void Block::block(int Num, int hNum){ 
    decision(Num, hNum);
        if(Life[hNum][Num] == 0){
        glBegin(GL_POLYGON);
        colorset(hNum);
        glVertex2f(blockx + (spownx * Num), blocky + (spowny * hNum));
        glVertex2f(blockx + 30 + (spownx * Num), blocky - 10 + (spowny * hNum));
        glVertex2f(blockx + 30 + (spownx * Num), blocky + 10 + (spowny * hNum));
        glVertex2f(blockx - 30 + (spownx * Num), blocky + 10 + (spowny * hNum));
        glVertex2f(blockx - 30 + (spownx * Num), blocky - 10 + (spowny * hNum));
        glVertex2f(blockx + 30 + (spownx * Num), blocky - 10 + (spowny * hNum));
        glEnd();
    }
}

// ブロックの色判定
void Block::colorset(int Num){
    (Num == 0 ? glColor3d(1.0, 0.0, 0.0) : Num == 1 ? glColor3d(1.0, 1.0, 0.0) : Num == 2 
              ? glColor3d(0.0, 1.0, 0.0) : Num == 3 ? glColor3d(0.0, 0.0, 1.0) : Num == 4
              ? glColor3d(1.0, 0.0, 1.0) : glColor3d(1.0, 1.0, 1.0));
}

// 画面表示
void display(){
    Ball b;
    Block blo[5][10];
    int i;
    int j;

    if(start == 0){     // スタート画面
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3d(1.0, 1.0, 1.0);
        DrawString("START", WIDTH, HEIGHT, 300, 240);
    }

    if(start == 1){
        glClear(GL_COLOR_BUFFER_BIT);

        player();   // 自機生成
        b.ball();   // 弾の生成

        for(i = 0; i <= 4; ++i){
            for(j = 0; j <= 9; ++j){
                blo[i][j].block(j, i);  // ブロックの生成
                glEnd();
            }   
        }
    }

    if(gameover == 1){  // ゲームオーバー画面
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3d(1.0, 0.0, 1.0);
        DrawString("Game over", WIDTH, HEIGHT, 290, 240);
        if(gameoveri == 0){
            channel6 = Mix_PlayChannel(-1, gameoverSE, 0);
            Mix_HaltMusic();
            gameoveri = 1;
        }
    }

    if(clear == 45){ // クリア画面
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3d(1.0, 1.0, 0.0);
        DrawString("Clear!", WIDTH, HEIGHT, 290, 240);
        if(cleari == 0){
            channel5 = Mix_PlayChannel(-1, clearSE, 1);
            Mix_HaltMusic();
            cleari = 1;
        }

    }

    glFlush();
    b.reverse();    // 壁と自機の当たり判定
}

void leftmove(){    // 自機左移動
    if(px + pmovex > 40){   // 左端の当たり判定
        pmovex -= 10.0;     
    }
    if(shoot == 0){ bx = bx - 10; };  // スタート、もしくはミスした時の挙動
}

void rightmove(){   // 自機右移動
    if(px + pmovex < 600){
        pmovex += 10.0;     // 右端の当たり判定
    }
    if(shoot == 0){ bx = bx + 10; };  // スタート、もしくはミスした時の挙動
}

void allmove(){
    if(start ==1){
        bx += l  * movex;   // x軸のボールの動き(仮)
        by += ll * movey;   // y軸のボールの動き(仮)       
    }
    if(leftm == 1){
        leftmove();     // 左移動
    }
    if(rightm == 1){
        rightmove();    // 右移動
    }
    glutPostRedisplay();
}

// キーを押した時の
void keydowan(unsigned char key, int x, int y){
    switch(key){
        case 's':
        case 'S':
        if(start == 0){
            start = 1;      // 最初のスタート画面からゲーム画面に移行する
            Mix_PlayMusic(music, -1);
        }
        break;

        case 'g':
        if(gameover == 1){  // ゲームオーバー画面に移行した時にウィンドウを閉じる
            exit(1);
        }

        case 'a':   // a を入力すると左に動く
        case 'A': 
        leftm = 1;  // 左移動の判定を出す
        break;

        case 'd':   // d を入力すると右に動く
        case 'D':
        rightm = 1; // 右移動判定を出す
        break;

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

        case ' ':
        if(shoot == 0){
            shoot = 1;
            movex = 0;
            movey = 4;
            channel4 = Mix_PlayChannel(-1, se4, 0);
        }

        break;

        case 'l':
            //Mix_PlayChannel(-1, chunk, 0);    // 効果再生

        default: 
        break;
    }
}

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

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

        default: break;

    }   
}

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 timer(int value){                  // 毎秒ごとに再描画して、アニメーションさせる
    glutIdleFunc(allmove);              // 弾と自機の移動
    glutTimerFunc(100, timer, 0);       // 第一引数毎秒で繰り返す
}

void init(){
    glClearColor(0.0, 0.0, 0.0, 1.0);   // 背景色 黒
}

/*SDLの初期設定*/
void SDLsetup(){

    if(0 != SDL_Init(SDL_INIT_AUDIO)){  // SDL初期化
        cout << "SDL setup error" << endl;
        exit(1);
    }                

    Mix_AllocateChannels(16);

    // SDL_Mixerオープン
    if(0 != Mix_OpenAudio(22050, AUDIO_S16,2,4096)){ 
        cout << "SDL mixer setup error" << endl;
        exit(1);
    }   

     /* ファイルから読み込む */
    music = Mix_LoadMUS("loop_113.wav");
    if(!music) { //ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

    se1 = Mix_LoadWAV("se_sac01.wav");
    if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

    se2 = Mix_LoadWAV("se_sab04.wav");
    if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

    se3 = Mix_LoadWAV("se_sab05.wav");
    if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

    se4 = Mix_LoadWAV("se_mod05.wav");
    if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

    clearSE = Mix_LoadWAV("clear.wav");
    if(!se1) { //ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

    gameoverSE = Mix_LoadWAV("tin1.wav");
    if(!se1) { // ファイル読み込みが失敗した場合、エラーの詳しい原因を出力
       cout << "failed to load music: " << Mix_GetError() << endl;
    }

}

/*2つの反射音を交互に鳴らす関数*/
void SEplay(){
    if(sedecision == 0){ // se判定の変数が0の時、効果音1を鳴らし、1を代入
        channel2 = Mix_PlayChannel(-1, se2, 0);
        sedecision = 1;
    }else{ // se判定の変数が0の時、効果音2を鳴らし、0を代入
        channel3 = Mix_PlayChannel(-1, se3, 0);
        sedecision = 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(keydowan);         // キーボードの入力挙動
    glutKeyboardUpFunc(keyup);          // 離した時の挙動
    glutTimerFunc(100, timer, 0);       // timer 関数内の実行
    glutReshapeFunc(reshape);           // 画面の再定義
    init();
    SDLsetup();
    glutMainLoop();
    return 0;
}

part1のコードに効果音と簡単なスタート画面、クリア画面、ゲームオーバー画面を付け加えたものです。音源ファイルはwav形式のものを使ってください。

開発環境
Mac version 10.10.5

ターミナルコマンド

g++ -o ファイル名.out ファイル名.cpp -mmacosx-version-min=10.8 -framework GLUT -framework OpenGL -lSDL2 -lSDL2_mixer

これからは3D処理のプログラムも触っていくと思うので、改めて計算方法を見直したいと思います。

4
2
2

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
4
2