ODEで学ぶC言語[Step3:関数]

step3

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

コメントを残す

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