物理エンジンODEで学ぶC言語[Step3:関数]

step3

ODEで学ぶC言語の3回目です.ODEの物理計算の部分は使わず,drawstuffを使った表示だけにします.
今回は今まで演習で作ったコードを整理して関数化しています.

まず,116行目のsimLoop関数から説明します.ここはシミュレーションで毎回呼び出される関数です.118行目のcollision関数でブロックが他のブロックと衝突しているかどうかの判定を行っています。衝突したら1を返し,それ以外は0を返します.衝突したら,新しいブロックを生成するためにnowを1増加させ,ブロックの位置を初期化しています.
122行目はブロックを表示し,123行目で壁を表示しています.

45行目のキー入力処理をするcommand関数では,ブロックを動かすa, dキーだけにしています.

61行目のdrawField関数ではフィールドを表示しています.ここでは,今後の処理のために,19行目にフィールドを表す,2次元配列mazeを宣言,初期化しています.要素1は壁,0は何もないことを示します.

80行目のinitBlock関数で,新しく生成したブロックの初期位置を設定しています.

109行目のcolllision関数は,未実装で演習問題になっています.現在,操作可能なブロックと他のブロックの距離を計算し,1[m]より小さい場合にブロック同士が衝突したと判定し1を返し,それ以外は0を返します.

説明はこのぐらいにして,ソースコードを読んで演習をしましょう.

/* step3  2013-07-03  */
#include "dm3.h"
#include <time.h>
#include <stdlib.h>

#define ROW       22  // フィールドの行数
#define COLUMN 11  // フィールドの列数

double R[12] = {1,0,0,0, 0,1,0,0, 0,0,1,0}; // 回転行列が格納される配列, 位置(x,y,z)[m]
double start_x =  5.5, start_y = 0.5, start_z = 0.0; // 壁の初期位置
double start_bx = 10.5, start_by = 20.5, start_bz = 0.5; // ブロックの初期位置

double wall_p[3] = {0.0, 0.0, 0.5};   // 壁の位置(x,y,z)[m]
double block_p[100][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       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} 
};

void command(int cmd)
{
    switch (cmd)
    {
    case 'a':
        if (block_p[now][0] > 1.5)  block_p[now][0] -= 1.0;
        break;
    case 'd':
        if (block_p[now][0] < 18.5) block_p[now][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)
            {
                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 initBlock()
{
    block_p[now][0] = start_bx;
    block_p[now][1] = start_by;
    block_p[now][2] = start_bz;
}

// ブロックの描画
void drawBlock()
{
    int i;

    if (block_p[now][1] >1.5)   // 下の壁を突き抜けない
    {
        block_p[now][1] -= 0.1; // ブロックの落下
    }
    else
    {
        now++;
        initBlock();
    }
    dsSetColor(1.0, 1.0, 0.0);   // 黄色

    for (i=0; i <= now; i++)
        dsDrawSphere(block_p[i], R, 0.5);
}

// ブロックが他のブロックと衝突したら1を返す,それ以外は0を返す
int collision()
{
    // ブロック間の距離が1未満なら1を返すコードを
    //  ここに書きなさい
     return 0;
}

void simLoop(int pause)        /***  シミュレーションループ ***/
{
    if (collision()) {
        now++;
        initBlock();
    }
    drawBlock(); // ブロックの表示
    drawField();   // フィールドの表示
}

int main()         /*** main関数 ***/
{
    initBlock();
    srand(time(NULL)); // 乱数の初期化
    dmLoop(800, 600); // シミュレーションループ ウインドウの幅,高
    return 0;
}

では,演習をしながら落ち物系パズルゲームを作っていきましょう.

演習

  1. step3-140702をダウンロードし,実行してください.
  2. collision関数を実装して,実行してください.
  3. 落ちるブロックの色を変更してください.
  4. ブロックが各行一杯になったら,その行のブロックを全て消すようにするためにはどうすればよいでしょうか.

コメントを残す

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