物理エンジンで学ぶC言語2015[STEP4:構造体]

step4

シューティングゲームの4回目です.今回は前回までの演習を構造体を使い実装しています.

まず,12行目から20行目で構造体myObjectを定義しています.メンバとしては,位置pos[3],回転行列R[12],質量m,半径r,サイズside[3],色*colorなどの変数です.

Step3との大きな違いは113行目のinitObject関数でゲームに使う物体を初期化しています.114行目のwelcomeMessage()で,ゲームのウェルカム表示と遊び方を表示します.具体的な遊び方は書いていないので,自分のオリジナルゲームを制作するときは、ユーザーが遊べるように遊び方を書きましょう.

また,Collision関数の引数がStep3では要素数3個の配列からmyObjecgt構造体に変更されています.

それ以外は,Step3とあまり違いはありません.Step3の演習は難しかったので,今回もほとんど同じにしています.構造体の復習を兼ねて,ソースコードを読んで演習をしましょう.


該当するソースコードは次のとおりです.

/* step4 */
/* A simple shooting game */
/* step4  2015-07-09      */
#include "dm4.h"
#include <time.h>
#include <math.h>
#include <stdlib.h>

#define TARGET_NUM 10   // 敵の数
#define BULLET_NUM 100  // 弾数

typedef struct myObject {
    double pos[3]; // 位置 x, y, z [m]
    double R[12];   // 回転行列 要素数4x3
    double m; // 質量 [kg]
    double r,l; // 半径 [m], 長さ [m]
    double side[3]; // サイズ x,y,z
    float *color; // 色 r,g,b
    int    hit; // 弾が当たった数
};

myObject target[TARGET_NUM];
myObject bullet[BULLET_NUM];
myObject robot;

int bullet_no = 0;
double start_x =0.0, start_y = 0.5, start_z = 0.5; // 初期位置
double R[12] = {1,0,0,0, 0,1,0,0, 0,0,1,0}; // 回転行列が格納される配列, 位置(x,y,z)[m]
double sides[3] = {1.0, 0.5, 1.0}; // 直方体のサイズ(x, y, z)[m]
static float blue[3] = {0.0, 0.0, 1.0}, red[3] = {1.0, 0, 0}, yellow[3] = {1.0, 1.0, 0}; // 青、赤、黄色

void setBullet(int no, double pos[3]) {
    bullet[no].pos[0] = pos[0];
    bullet[no].pos[1] = pos[1];
    bullet[no].pos[2] = pos[2];
}

void command(int cmd) {
    switch (cmd) {
    case 'a':
        robot.pos[0] -= 1.0;
        break;
    case 'd':
        robot.pos[0] += 1.0;
        break;
    case 'x':
        robot.pos[1] -= 1.0;
        break;
    case 'w':
        robot.pos[1] += 1.0;
        break;
    case 32:
        setBullet(bullet_no,robot.pos);
        bullet_no++;
        printf("bullet=%d\n",bullet_no);
        break;
    default:
        printf("Input %c (%d)\n",(char)cmd, cmd);
    }
}

void drawTarget() {
    int i;
    for (i = 0; i < TARGET_NUM; i++) {
        if (target[i].hit) continue;
        dsSetColor(target[i].color[0],target[i].color[1],target[i].color[2]); // 色の設定
        dsDrawBox(target[i].pos,target[i].R,target[i].side); // 直方体の表示
    }
}

void drawBullet() {
    int i;
    for (i=0; i< BULLET_NUM; i++) {
        dsSetColor(bullet[i].color[0], bullet[i].color[1], bullet[i].color[2]); // 色の設定
        dsDrawSphere(bullet[i].pos,bullet[i].R, bullet[i].r); // 球の表示
    }
}

void drawRobot() {
    // ロボットの表示
    dsSetColor(robot.color[0], robot.color[1], robot.color[2]);   // 黄色
    dsDrawSphere(robot.pos, robot.R, robot.r);
}

// ブロックが他のブロックと衝突したら1を返す,それ以外は0を返す
int collision(myObject a, myObject b) {
    // ブロック間の距離が1未満なら1を返すコードを
    //  ここに書きなさい
    double dist = sqrt((a.pos[0]- b.pos[0]) * (a.pos[0]-b.pos[0])
                       + (a.pos[1]-b.pos[1]) * (a.pos[1]-b.pos[1]));
    if (dist < 0.5) return 1;
    else            return 0;
}

void simLoop(int pause) {      /***  シミュレーションループ ***/
    int i,j;


    for (i=0; i < bullet_no; i++) {
        bullet[i].pos[1] += 0.01;
        for (j = 0; j < TARGET_NUM; j++) {
            if (collision(bullet[i],target[j])) {
                target[j].hit = 1;
            }
        }
    }
    drawBullet();
    drawTarget();  // 敵の描画
    drawRobot();   // ロボットの描画
}

// 物体の初期化
void initObject() {
    int i, j, k, c;

    // 敵
    for (i =0; i < TARGET_NUM; i++) {
        target[i].pos[0] = 2 * i  + start_x - TARGET_NUM + 1;  // 位置のx成分
        target[i].pos[1] = start_y + 10;       // 位置のx成分
        target[i].pos[2] = 0.5;
        target[i].color = blue;
        target[i].hit   = 0;
        for (k = 0; k < 12; k++) target[i].R[k] = R[k];
        for (j = 0; j < 3; j++)  target[i].side[j] = sides[j];
    }

    // ロボット
    robot.pos[0] = start_x;
    robot.pos[1] = start_y - 10;
    robot.pos[2] = start_z;
    robot.color  = yellow;
    for (k = 0; k < 12; k++) robot.R[k] = R[k];
    robot.r      = 0.5;

    // 弾
    for (i =0; i < BULLET_NUM; i++) {
        for (j=0; j < 3; j++) bullet[i].pos[j] = robot.pos[j];
        bullet[i].color = red;
        for (k = 0; k < 12; k++) bullet[i].R[k] = R[k];
        bullet[i].r = 0.1;
    }
}

void welcomeMessage() {
    printf("****************************************\n");
    printf("* Welcom to the Simple Shooting Game ! *\n");
    printf("****************************************\n\n");
    printf(" Please write here. how to play.\n");
}

int main() {       /*** main関数 ***/
    welcomeMessage();
    initObject(); // 物体の初期化
    dmLoop(800, 600); // シミュレーションループ ウインドウの幅,高
    return 0;
}

演習

  1. step4-150709.zipをダウンロードし,実行してください.
  2. 遊び方を表示するwelcomeMessage()を自分の好きなように変えよう!
  3. サンプルでは弾が1発当たると敵は破壊されましたが,1発命中すると敵の色が赤くように改良しよう!
  4. サンプルでは弾が1発当たると敵は破壊されましたが,1発命中すると敵の色が赤くなり,2発目で破壊するように改良しよう!
  5. 敵がインベーダーゲームのように移動するように改良しよう!
  6. 敵も弾を発射するように改良しよう!
  7. 敵の弾が自分のロボットに命中したら,ゲームオーバーにするよう改良しよう!また,敵を1台破壊したら10点入るようにし,Scoreを表示しよう.
  8. ロボットの初期位置に弾が残って表示されるバグがあります。バグを取ろう!

コメントを残す

メールアドレスが公開されることはありません。