前項までのプログラムでは、どのタイプの敵キャラでも同じテクスチャを使っている。ここでは、タイプによってテクスチャ画像を切り替えて表示する方法を紹介する。
この章で使用する画像ファイル
タイプ別に敵キャラの画像を変えるのが一番シンプルであるが、そうとは限らない。例えば右上から現れて左下に移動する敵キャラと、左上から現れて右下に移動する敵キャラは、初期化データは違うためにタイプが違うと考えられるが、右から出るか左から出るかの違いだけで、動き自体に差はほとんど無い。こういった敵キャラは、同じ画像を使うことが多い。

よって、タイプが違えば画像も違うが、違うタイプでも同じ画像を使う場合もあると考えたほうが、汎用性のあるプログラムを作成できるだろう。
では実際に、プログラムに組み込む方法を解説する。この章で使用するビットマップファイルをダウンロード・解凍し、ソースファイルと同じフォルダ内へ配置しておくこと。
敵キャラ用の画像を3つ用意した。この3つの画像のテクスチャを作成し、5つのタイプの敵キャラで使用する。
今回は、どのステージでも同じ敵キャラ画像を使うため、ゲーム開始時初期化処理(GameInit関数)でテクスチャを作成するが、ステージごとに使う画像を変える場合、ステージ別初期化処理(GameStageInit関数)で行ったほうがよい。
//-----------------------------------------------------------------------------
// 共通ヘッダ・ファイル
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
・
・
・
// マクロ
/* 頂点フォーマット(基本形)*/
#define FVF_TLVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
/* ゲームの状態を識別する(フレーム番号) */
#define START_INIT 0
#define START_FRAME 1
#define GAME_INIT 10
#define GAME_STAGEINIT 11
#define GAME_FRAME 12
#define GAMEOVER_INIT 80
#define GAMEOVER_FRAME 81
#define GAMECLEAR_INIT 90
#define GAMECLEAR_FRAME 91
/* その他のマクロ */
#define SCREEN_WIDTH 640 // ウィンドウの幅
#define SCREEN_HEIGHT 480 // ウィンドウの高さ
#define RELEASE(x) if(x!=NULL){x->Release();x=NULL;} // オブジェクトの開放
#define DEBUG true // デバッグ・モード(使わないときはコメントアウト)
#define DEAD 0 // 死亡フラグ
#define ENEMYBMPMAX 3 // 敵キャラ画像の最大
・
・
・
//============================================================================= // DirectX Graphics関係の自作関数群 // Copyright NKC Game Staff(←自分の名前) //----------------------------------------------------------------------------- #include "NKC_Common.h" // グローバル変数 /* 他のソースからも利用されるもの */ LPDIRECT3DDEVICE8 gl_lpD3ddev = NULL; // Direct3DDevice8インターフェイス LPDIRECT3DTEXTURE8 gl_TXBack = NULL; // 背景用テクスチャ LPDIRECT3DTEXTURE8 gl_TXMenu = NULL; // メニュー用テクスチャ LPDIRECT3DTEXTURE8 gl_TXCursor = NULL; // メニュー選択カーソル用テクスチャ LPDIRECT3DTEXTURE8 gl_TXMyChara = NULL; // 自機用テクスチャ LPDIRECT3DTEXTURE8 gl_TXEnemy[ENEMYBMPMAX] = {NULL,NULL,NULL}; // 敵用テクスチャ ・ ・ ・ //----------------------------------------------------------------------------- // 関数名 : CreateGameTexture() // 機能概要: ゲーム画面用テクスチャの作成・再生成 //----------------------------------------------------------------------------- void CreateGameTexture(void) { HRESULT hr; char* szEnemyImg[] = {"enemy0.bmp","enemy1.bmp","enemy2.bmp"}; // 敵キャラファイル名 int i; char buff[80]; // 自機用テクスチャを生成 hr = D3DXCreateTextureFromFileEx( gl_lpD3ddev, "mychara.bmp", // ファイル名 0, 0, 0, 0, D3DFMT_A1R5G5B5, // 色抜きを可能に D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, D3DCOLOR_ARGB(255, 255, 255, 255),// 白色を透過色とする NULL, NULL, &gl_TXMyChara // テクスチャ名 ); if ( FAILED(hr) ) { MessageBox(hWnd, "mychara.bmp をテクスチャとして読み込めませんでした", "ERROR", MB_OK); return; } // 敵用テクスチャを生成 for ( i=0 ; i<ENEMYBMPMAX ; i++ ) { hr = D3DXCreateTextureFromFileEx( gl_lpD3ddev, szEnemyImg[i], // ファイル名 0, 0, 0, 0, D3DFMT_A1R5G5B5, // 色抜きを可能に D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, D3DCOLOR_ARGB(255, 21, 141, 91),// 透過色を指定 NULL, NULL, &gl_TXEnemy[i] // テクスチャ名 ); if ( FAILED(hr) ) { wsprintf(buff, "%s をテクスチャとして読み込めませんでした", szEnemyImg[i]); MessageBox(hWnd, buff, "ERROR", MB_OK); return; } } } //----------------------------------------------------------------------------- // 関数名 : ReleaseGameTexture() // 機能概要: ゲーム画面用テクスチャ開放処理 //----------------------------------------------------------------------------- void ReleaseGameTexture(void) { int i; // テクスチャの開放 RELEASE(gl_TXBack); // 背景 RELEASE(gl_TXMyChara); // 自キャラ for ( i=0 ; i<ENEMYBMPMAX ; i++ ) RELEASE(gl_TXEnemy[i]); // 敵キャラ }
//-----------------------------------------------------------------------------
// File: NKC_DGraphics.h
// Desc: NKC_DGraphics.cppで使用するもののうち、他のソースでも使うものを宣言
//-----------------------------------------------------------------------------
・
・
・
//-----------------------------------------------------------------------------
// グローバル変数
//-----------------------------------------------------------------------------
extern LPDIRECT3DDEVICE8 gl_lpD3ddev; // Direct3DDevice8インターフェイス
extern LPDIRECT3DTEXTURE8 gl_TXBack; // 背景用テクスチャ
extern LPDIRECT3DTEXTURE8 gl_TXMenu; // メニュー用テクスチャ
extern LPDIRECT3DTEXTURE8 gl_TXCursor; // メニュー選択カーソル用テクスチャ
extern LPDIRECT3DTEXTURE8 gl_TXMyChara; // 自機用テクスチャ
extern LPDIRECT3DTEXTURE8 gl_TXEnemy[ENEMYBMPMAX]; // 敵用テクスチャ
・
・
・
//=============================================================================
// ゲーム処理関係の自作関数群
// Copyright NKC Game Staff(←自分の名前)
//-----------------------------------------------------------------------------
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : EnemyDraw()
// 機能概要: 敵キャラ描画
//-----------------------------------------------------------------------------
static void EnemyDraw(void)
{
int i;
gl_lpD3ddev->SetTexture(0, gl_TXEnemy[0]);
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > DEAD )
gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Enemy[i].Vertex, sizeof(TLVERTX));
}
}
・
・
・
ここまでの修正を行い、敵キャラ用テクスチャの要素を0,1,2にそれぞれセットしてみて、テクスチャが切り替わるかを確認する。
敵キャラの種類(タイプ)よって、使用するテクスチャが変化するよう、プログラムを修正する。
//-----------------------------------------------------------------------------
// 関数名 : EnemyDraw()
// 機能概要: 敵キャラ描画
//-----------------------------------------------------------------------------
static void EnemyDraw(void)
{
int i, j;
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > DEAD ) {
switch ( Enemy[i].type ) {
case 0: j = 0; break;
case 1:
case 2: j = 1; break;
case 3:
case 4: j = 2; break;
}
gl_lpD3ddev->SetTexture(0, gl_TXEnemy[j]);
gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Enemy[i].Vertex, sizeof(TLVERTX));
}
}
}
ここまでの修正を行い、テクスチャが正しく変化するかを確認する。
先に紹介したやり方の場合、プログラミングは楽かもしれないが、描画(ゲームループ)のたびに判定が行われるため、処理効率が悪い。
描画処理が実行されるたびに使用するテクスチャの判定を行うのではなく、敵キャラ発生時に使用するテクスチャをセットする方法を紹介する。
/* キャラクタ情報構造体 */
typedef struct _STATUS {
TLVERTX Vertex[4]; // 頂点情報配列
RECT HitRect; // 当たり判定矩形情報
float MoveX, MoveY; // 移動量
int type; // タイプ
LPDIRECT3DTEXTURE8 Texture; // テクスチャ
int flg; // フラグ(表示:1以上 非表示:0)
} STATUS, *LPSTATUS;
//-----------------------------------------------------------------------------
// 関数名 : SetEnemyInit()
// 機能概要: 敵キャラ発生用データ初期化
//-----------------------------------------------------------------------------
static void SetEnemyInit(LPSTATUS pEnemyInit,
float x1, float y1, float x2, float y2,
LONG left, LONG right, LONG top, LONG bottom,
float mx, float my,
int type, int life)
{
InitVertex(pEnemyInit->Vertex, x1, y1, x2, y2); // 表示位置
SetRect(&pEnemyInit->HitRect, left, top, right, bottom); // 当たり判定矩形
pEnemyInit->MoveX = mx; // 移動量(X方向)
pEnemyInit->MoveY = my; // 移動量(Y方向)
pEnemyInit->type = type; // タイプ
switch ( type ) { // テクスチャ
case 0: pEnemyInit->Texture = gl_TXEnemy[0]; break;
case 1:
case 2: pEnemyInit->Texture = gl_TXEnemy[1]; break;
case 3:
case 4: pEnemyInit->Texture = gl_TXEnemy[2]; break;
}
pEnemyInit->life = life; // ライフ
}
//-----------------------------------------------------------------------------
// 関数名 : EnemyDraw()
// 機能概要: 敵キャラ描画
//-----------------------------------------------------------------------------
static void EnemyDraw(void)
{
int i;
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > DEAD ) {
gl_lpD3ddev->SetTexture(0, Enemy[i].Texture);
gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, Enemy[i].Vertex, sizeof(TLVERTX));
}
}
}
※ここまでの修正を行い、テクスチャが正しく変化するかを確認する。
どちらのやり方がいいのかは、処理効率を優先するのか、プログラムの見易さを優先するのか、メモリの使用量を優先するのかなど、何を優先するかによって変わる。自分が作成するゲームではどのやり方が一番いいのかを常に考えながら、Case by Caseで使い分けよう。
| BACK(タイプ別に初期化データを変える) | NEXT(自キャラから弾を出す) |