敵キャラを簡単に増加させる

この章で使用する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;
・
・
・

《POINT》

ゲーム処理で使用するマクロ・グローバル変数の宣言

現在の時間は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;          // 敵キャラ出現時間
・
・
・

《POINT》

初期化処理(StartInit関数)

敵キャラ情報の初期化が次のように変更になる。

//-----------------------------------------------------------------------------
// 関数名 : 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;

}

《POINT》

ゲーム処理(GameFrame関数)

ゲーム処理は次のようになる。

//-----------------------------------------------------------------------------
// 関数名 : 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;
    }

}

《POINT》

※以上の修正を行ったらプログラムをビルド・実行し、0.5秒ごとに敵キャラが現れ、最大5匹まで増えることを確認しよう。


BACK(キャラクタ用構造体変数の作り方と使い方) NEXT(キャラクタ構造体を使うメリットを考える)