この章で使用するGame.cpp(入れ替えること)
キャラクタ構造体を用いることにより、キャラクタ情報を効率的に管理できるようになった。応用として、構造体の特長を最大限に生かしつつ、敵キャラを一定時間ごとに増加させるプログラムを考えてみる。
敵キャラを表示するかどうかを判断するための情報を、キャラクタ構造体に追加する。キャラクタ構造体は共通ヘッダ・ファイルに宣言してあるため、common.hを次のように修正する。
//-----------------------------------------------------------------------------
// 共通ヘッダ・ファイル
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
・
・
・
// 構造体の宣言
/* 頂点構造体 */
typedef struct _TLVERTEX {
float x, y, z; //位置情報
float rhw; //頂点変換値
D3DCOLOR color; //頂点カラー
float tu, tv; //テクスチャ座標
} TLVERTX, *LPTLVERTEX;
/* キャラクタ情報構造体 */
typedef struct _STATUS {
TLVERTX Vertex[4]; // 頂点情報配列
RECT HitRect; // 当たり判定矩形情報
float MoveX, MoveY; // 移動量
int life; // ライフ(表示:1以上 非表示:0)
} STATUS, *LPSTATUS;
・
・
・
現在の時間はWinMain.cppで取得済みであるため、game.cppのみの変更となる。マクロとグローバル変数の宣言を次のように行う。
//============================================================================= // ゲーム処理関係の自作関数群 // Copyright NKC Game Staff(←自分の名前) //----------------------------------------------------------------------------- #include "NKC_Common.h" // マクロの定義 #define ENEMYMAX 5 #define ENEMYTIME 5000 // グローバル変数 /* 自ソースでのみ利用するもの */ //---- 背景 static TLVERTX BackVertex[4]; // 頂点情報配列 //---- 自機 static STATUS MyChara; // 自キャラステータス情報 //---- 敵 static STATUS EnemyInitData; // 敵キャラステータス情報初期化データ static STATUS Enemy[ENEMYMAX]; // 敵キャラステータス情報 static DWORD gl_EnemyTime; // 敵キャラ出現時間 ・ ・ ・
敵キャラ情報の初期化が次のように変更になる。
//-----------------------------------------------------------------------------
// 関数名 : GameInit()
// 機能概要: ゲーム画面初期化処理
//-----------------------------------------------------------------------------
void GameInit(void)
{
int i;
//--------------------------------------------------- 各変数の初期化
// ゲーム画面で使用するテクスチャの作成
CreateGameTexture();
// ポリゴンの初期化
/* 背景 */
InitVertex(BackVertex, (float)gl_rcScreen.left, (float)gl_rcScreen.top, (float)gl_rcScreen.right, (float)gl_rcScreen.bottom, 255); // 頂点データ
/* 自キャラ */
InitVertex(MyChara.Vertex, 100.0f, 100.0f, 164.0f, 164.0f, 255); // 頂点データ
SetRect(&MyChara.HitRect, 10, 15, 10, 15); // 当たり判定矩形
MyChara.MoveX = 2.0f;
MyChara.MoveY = 2.0f;
/* 敵キャラ初期化データ */
InitVertex(EnemyInitData.Vertex, 400.0f, 300.0f, 496.0f, 396.0f, 255); // 頂点データ
SetRect(&EnemyInitData.HitRect, 5, 5, 5, 5); // 当たり判定矩形
EnemyInitData.MoveX = 3.0f;
EnemyInitData.MoveY = 3.0f;
EnemyInitData.life = 1;
/* 敵キャラ */
for ( i=0 ; i<ENEMYMAX ; i++ ) Enemy[i].life = 0;
/* 敵キャラ出現時間のクリア */
gl_EnemyTime = 0;
//--------------------------------------------------- フレームナンバーセット
g_FrameNo = GAME_FRAME;
}
ゲーム処理は次のようになる。
//-----------------------------------------------------------------------------
// 関数名 : GameFrame()
// 機能概要: ゲーム画面処理
//-----------------------------------------------------------------------------
void GameFrame(void)
{
int i;
float mx, my; // 移動量
//--------------------------------------------------- 敵キャラの出現
if ( gl_nowTime - gl_EnemyTime <= ENEMYTIME ) {
gl_EnemyTime = gl_nowTime;
/* lifeが0のデータを検索し、初期情報をセット(敵キャラが死ぬことを考えてある) */
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life == 0 ) {
Enemy[i] = EnemyInitData; // 一括代入
break; // 見つかれば、for文を抜ける
}
}
}
//--------------------------------------------------- 描画処理
// 背景
gl_lpD3ddev->SetTexture(0, gl_TXBack);
gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, BackVertex, sizeof(TLVERTX));
// 自キャラ
gl_lpD3ddev->SetTexture(0, gl_TXMyChara);
gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, MyChara.Vertex, sizeof(TLVERTX));
// 敵キャラ
gl_lpD3ddev->SetTexture(0, gl_TXEnemy);
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > 0 )
gl_lpD3ddev-<DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Enemy[i].Vertex, sizeof(TLVERTX));
}
//--------------------------------------------------- 移動処理
// 自キャラ
mx = my = 0.0f;
if ( gl_KeyTbl[VK_LEFT] & 0x80 ) mx = -MyChara.MoveX;
if ( gl_KeyTbl[VK_UP] & 0x80 ) my = -MyChara.MoveY;
if ( gl_KeyTbl[VK_RIGHT] & 0x80 ) mx = MyChara.MoveX;
if ( gl_KeyTbl[VK_DOWN] & 0x80 ) my = MyChara.MoveY;
Move(MyChara.Vertex, mx, my);
MoveCheck(gl_rcScreen, MyChara.Vertex); // 指定範囲を超えないようにする
// 敵キャラ
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > 0 ) {
Move(Enemy[i].Vertex, Enemy[i].MoveX, Enemy[i].MoveY);
MoveCheck(gl_rcScreen, Enemy[i].Vertex); // 指定範囲を超えないようにする
if ( Enemy[i].Vertex[0].x == gl_rcScreen.left || gl_rcScreen.right == Enemy[i].Vertex[2].x ) Enemy[i].MoveX *= (-1.0);
if ( Enemy[i].Vertex[0].y == gl_rcScreen.top || gl_rcScreen.bottom == Enemy[i].Vertex[2].y ) Enemy[i].MoveY *= (-1.0);
}
}
//--------------------------------------------------- 当たり判定
// 自キャラと敵キャラ
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > 0 ) {
if ( HitCheck2(MyChara.Vertex, MyChara.HitRect, Enemy[i].Vertex, Enemy[i].HitRect) ) {
ReleaseGameTexture();
g_FrameNo = START_INIT;
}
}
}
// F1が押されたら、スタート画面に戻る(デバッグ用)
if ( gl_KeyTbl[VK_F1] & 0x80 ) {
ReleaseGameTexture();
g_FrameNo = START_INIT;
}
}
※以上の修正を行ったらプログラムをビルド・実行し、0.5秒ごとに敵キャラが現れ、最大5匹まで増えることを確認しよう。
| BACK(キャラクタ用構造体変数の作り方と使い方) | NEXT(キャラクタ構造体を使うメリットを考える) |