ODEで学ぶC言語の3回目です.ODEの物理計算の部分は使わず,drawstuffを使った表示だけにします.
今回は今まで演習で作ったコードを整理して関数化しています.
まず,138行目のsimLoop関数から説明します.ここはシミュレーションで毎回呼び出される関数です.140行目のcollision関数でロボットがおばけに食べられたかどうか判定して,食べられたら1を返し,それ以外は0を返します.0の場合はロボットのシミュレーション関数simRobotを呼び出し,1の場合は”Game over!”と表示します.
145~147行目はおばけを表示し,149行目で壁を表示しています.
44行目のキー入力処理をするcommand関数では,ロボットを動かすa, d, x, wキーの他に,ゲーム再スタートをさせるrキーの処理を加えています.死んだことになるdeathを0にして生き返らせ,ロボットの初期位置を設定しています.
72行目のsimWall関数では壁を表示しています.ここでは,いろいろな迷路をつくれるように,20行目に迷路を地図を表す,2次元配列mazeを宣言,初期化しています.要素1は壁,0は何もないことを示します.
92行目のおばけのシミュレーション関数simObakeでは,おばけの色と形を決め,各おばけ毎の動作を決めています.
125行目のcolllision関数は,ロボットと各おばけの距離を計算し,1[m]より小さい場合にロボットがおばけに食べられたと考え1を返し,それ以外は0を返します.
説明はこのぐらいにして,ソースコードを読んで演習をしましょう.
/* step3 2013-07-07 */ #include "dm3.h" #include <time.h> #include <stdlib.h> #define ROW 20 // 迷路の行数 #define COLUMN 20 // 迷路の列数 double R[12] = {1,0,0,0, 0,1,0,0, 0,0,1,0}; // 回転行列が格納される配列, 位置(x,y,z)[m] double start_x = 0.5, start_y = 0.5, start_z = 0.0; // 迷路の初期位置 double wall_p[3] = {0.0, 0.0, 0.5}; // 壁の位置(x,y,z)[m] double robot_p[3] = {10.5,10.5, 0.5}; // ロボットの位置 double obake1_p[3] = {2.5, 2.5, 0.5}; // おばけ1の初期位置 double obake2_p[3] = {7.5, 8.5, 0.5}; // おばけ2の初期位置 double obake3_p[3] = {1.5, 6.5, 0.5}; // おばけ3の初期位置 double sides[3] = {1.0, 1.0, 1.0}; // 直方体のサイズ(x, y, z)[m] float black[3] = {0, 0, 0}, green[3] = {0,1,0},red[3] = {1,0,0}; // 黒色,緑色,赤色 int death = 0; int maze[ROW][COLUMN] = // 迷路 { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, // 10 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} // 20 }; void command(int cmd) /*** キー処理関数 ***/ { switch (cmd) { case 'a': if (robot_p[0] > 1.5) robot_p[0] -= 1.0; break; case 'd': if (robot_p [0] < 18.5) robot_p[0] += 1.0; break; case 'x': robot_p[1] -= 1.0; break; case 'w': robot_p[1] += 1.0; break; case 'r': death = 0; robot_p[0] = 10.5; robot_p[1] = 10.5; robot_p[2] = 0.5; printf("Game restart!\n"); break; default: printf("Inputted key is %c: Input a, d, w, x, r \n",(char)cmd); } } void simWall() /*** 壁のシミュレーション ***/ { int i, j; for (i = 0; i < ROW; i++) { for (j = 0; j < COLUMN; j++) { if (maze[i][j] == 1) { dsSetColor(1.0, 0.0, 0.0); // 色の設定 wall_p[0] = j + start_x; // 位置のx成分 wall_p[1] = i + start_y; // 位置のx成分 wall_p[2] = 0.5; // 位置のz成分 dsDrawBox(wall_p,R,sides); // 直方体の表示 } } } } /*** おばけのシミュレーション ***/ void simObake(int no, double p[3], float color[3]) { static int dir1 =1,dir2=1, dir3=1; double speed = 0.08; dsSetColor(color[0], color[1], color[2]); // 色設定 dsDrawCapsule(p, R, 0.5, 0.5); switch (no) { case 1: if ((p[0] < 1.5) || (p[0] > 18.5)) dir1 *= -1; p[0] += dir1 * speed; break; case 2: if ((p[1] < 1.5) || (p[1] > 18.5)) dir2 *= -1; p[1] += dir2 * speed; break; case 3: if ((p[0] < 1.5) || (p[0] > 18.5)) dir3 *= -1; p[0] += dir3 * speed; break; default: printf("Error obake\n"); } } void simRobot() /*** ロボットのシミュレーション ***/ { dsSetColor(1.0, 1.0, 0.0); // 黄色 dsDrawSphere(robot_p,R, 0.5); } /*** ロボットがおばけに捕獲されたら1,それ以外は0を返す ***/ int collision() { double r1, r2, r3; r1 = (robot_p[0]-obake1_p[0]) * (robot_p[0]-obake1_p[0]) + (robot_p[1]-obake1_p[1]) * (robot_p[1]-obake1_p[1]); r2 = (robot_p[0]-obake2_p[0]) * (robot_p[0]-obake2_p[0]) + (robot_p[1]-obake2_p[1]) * (robot_p[1]-obake2_p[1]); r3 = (robot_p[0]-obake3_p[0]) * (robot_p[0]-obake3_p[0]) + (robot_p[1]-obake3_p[1]) * (robot_p[1]-obake3_p[1]); if (r1 <1 || r2 < 1 || r3 < 1) return 1; else return 0; } void simLoop(int pause) /*** シミュレーションループ ***/ { if (death == 0) death = collision(); // ロボットの生死判定 if (death == 0) simRobot(); // ロボットの表示 else printf("Game over!\n"); simObake(1, obake1_p, black); // おばけ1の表示 simObake(2, obake2_p, red); // おばけ2の表示 simObake(3, obake3_p, green); // おばけ3の表示 simWall(); // 壁の表示 } int main() /*** main関数 ***/ { srand(time(NULL)); // 乱数の初期化 dmLoop(800, 600); // シミュレーションループ ウインドウの幅,高 return 0; }
演習:以下の機能を追加してパックマン風ゲームを完成させよう.
1.step3-130708.zipをダウンロードして実行しよう.
2. 迷路を複雑にしよう.
3. このプログラムではロボット,おばけが迷路内の壁を通り抜けてしまいます.通り抜けないように変更しよう.
4. おばけの動きを壁に沿って進むように変更しよう.
5. 迷路の中に餌(直径20cmの球,色は任意)をばらまき,ロボットが餌の0.5m以内に近づいたら,得点を10点加算させ,その餌を表示しないようにしよう.
6. その他,必要な機能を追加しオリジナルパックマン風ゲームを完成させよう.
コメント