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. その他,必要な機能を追加しオリジナルパックマン風ゲームを完成させよう.

コメント