ODEで学ぶC言語の4回目です.ODEの物理計算の部分は使わず,drawstuffを使った表示だけにします.今回は前回までの演習を構造体を使い実装しています.
まず,10行目から18行目で構造体myObjectを定義しています.メンバとしては,位置p[3],回転行列R[12],質量m,半径r,サイズside[3],色*colorなどの変数です.
Step3との大きな違いは93行目のinitObject関数でゲームに使う物体を初期化しています.前回の演習で各ブロック色を割り当てる問題がありましたが,この関数でそれを解決しています.
また,前回のもう一つの課題であったCollision関数は136から148行目にかけて定義しています.ここで,block[i].p[j]はブロック(i番目)の位置(j座標)という意味です.nowは現在,着目しているブロックの番号でしたね.
それ以外は,Step3とあまり違いはありません.構造体の復習を兼ねて,ソースコードを読んで演習をしましょう.
/* step4 2014-07-10 */ #include "dm4.h" #include <time.h> #include <stdlib.h> #define NUM 200 // ブロック数 #define ROW 22 // フィールドの行数 #define COLUMN 11 // フィールドの列数 typedef struct myObject { double p[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 } ; myObject block[NUM]; // ブロック myObject wall; // 壁 double R[12] = {1,0,0,0, 0,1,0,0, 0,0,1,0}; // 回転行列が格納される配列, 位置(x,y,z)[m] double start_wall_p[3] = {5.5, 0.5, 0.0}; // 壁の初期位置 double start_block_p[3] = {10.5, 20.5, 0.5}; // ブロックの初期位置 double side[3] = {1.0, 1.0, 1.0}; // 直方体のサイズ(x, y, z)[m] float black[3] = {0,0,0}, white[3] = {1.5,1.5,1.5}, red[3] = {1.5, 0, 0}; // 黒、白 int now = 0; // 現在、操作可能なブロック番号 int field[ROW][COLUMN] = // フィールド { {1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1} // 20 }; void command(int cmd) { switch (cmd) { case 'a': if (block[now].p[0] > 1.5) block[now].p[0] -= 1.0; break; case 'd': if (block[now].p[0] < 18.5) block[now].p[0] += 1.0; break; default: printf("Key is %c: Input a,d,w,x,r\n",(char)cmd); } } // フィールドのシミュレーション void drawField() { int i, j; for (i = 0; i < ROW; i++) { for (j = 0; j < COLUMN; j++) { if (field[i][j] == 1) { wall.p[0] = j + start_wall_p[0]; // 位置のx成分 wall.p[1] = i + start_wall_p[1]; // 位置のx成分 wall.p[2] = 0.5; // 位置のz成分 dsSetColor(wall.color[0], wall.color[1], wall.color[2]); dsDrawBox(wall.p, wall.R, wall.side); // 直方体の表示 } } } } // 物体の初期化 void initObject() { int i, j, k, c; // ブロック for (i =0; i < NUM; i++) { for (j = 0; j < 3; j++) block[i].p[j] = start_block_p[j]; for (k = 0; k < 12; k++) block[i].R[k] = R[k]; // 乱数で色を生成 c = rand() % 2; if (c == 0) block[i].color = black; else block[i].color = white; } // 壁 for (j = 0; j < 3; j++) wall.side[j] = side[j]; for (k = 0; k < 12; k++) wall.R[k] = R[k]; wall.color = red; } // ブロックの描画 void drawBlock() { int i; if (block[now].p[1] >1.5) // 下の壁を突き抜けない { block[now].p[1] -= 0.1; // ブロックの落下 } else { now++; } dsSetColor(1.0, 1.0, 0.0); // 黄色 for (i=0; i <= now; i++) { dsSetColor(block[i].color[0], block[i].color[1], block[i].color[2]); dsDrawSphere(block[i].p, R, 0.5); } } // ブロックが他のブロックと衝突したら1を返す,それ以外は0を返す int collision() { int i,j; double r=0; for (i=0; i < now; i++) { for (j=0; j < 3; j++) { r += (block[i].p[j]-block[now].p[j]) *(block[i].p[j]-block[now].p[j]); } if (r < 1) return 1; else r = 0; } return 0; } void simLoop(int pause) /*** シミュレーションループ ***/ { if (collision()) { now++; //initBlock(); } drawBlock(); // ブロックの表示 drawField(); // フィールドの表示 } int main() /*** main関数 ***/ { initObject(); srand(time(NULL)); // 乱数の初期化 dmLoop(800, 600); // シミュレーションループ ウインドウの幅,高 return 0; }
では,演習をしながら落ち物系パズルゲームを作っていきましょう.
演習
- step4-140710.zipをダウンロードし,実行しよう!
- ブロックが各行一杯になったら,その行のブロックを全て消そう!
- 複数の結合したブロックが落ちるように改良しよう!
- 同じ色のブロックが上下左右4方向にあると,その色のブロックは消えるようにしよう!
- 得点表示をしよう!
- これを改良して最終課題を考えよう!
コメント