シューティングゲームのように、自キャラから弾を発射する方法を紹介する。
ゲーム画面でスペースキーを押したとき、弾を発射するようプログラムを考える。弾は1発しか発射できず、画面から消えるまで次の弾を発射することはできないものとする(インベーダーのイメージ)。
自ショット用画像ファイルをダウンロードし、ソースファイルと同じフォルダに配置しておくこと。
//============================================================================= // 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_TXMyShot = NULL; // 自弾用テクスチャ LPDIRECT3DTEXTURE8 gl_TXEnemy[ENEMYBMPMAX] = {NULL,NULL,NULL}; // 敵用テクスチャ /* 自ソースでのみ利用するもの */ static LPDIRECT3D8 gl_lpD3d = NULL; // Direct3D8インターフェイス static D3DPRESENT_PARAMETERS gl_d3dpp; // ディスプレイパラメータ ・ ・ ・ //----------------------------------------------------------------------------- // 関数名 : 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; } // 自弾用テクスチャを生成 hr = D3DXCreateTextureFromFileEx( gl_lpD3ddev, "myshot.bmp", // ファイル名 0, 0, 0, 0, D3DFMT_A1R5G5B5, // 色抜きを可能に D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, D3DCOLOR_ARGB(255, 21, 141, 91), // 透過色を指定 NULL, NULL, &gl_TXMyShot // テクスチャ名 ); if ( FAILED(hr) ) { MessageBox(hWnd, "myshot.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); // 自キャラ RELEASE(gl_TXMyShot); // 自弾 for ( i=0 ; i<ENEMYBMPMAX ; i++ ) RELEASE(gl_TXEnemy[i]); // 敵キャラ }
//-----------------------------------------------------------------------------
// File: myDGraphics.h
// Desc: myDGraphics.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_TXMyShot; // 自弾用テクスチャ
extern LPDIRECT3DTEXTURE8 gl_TXEnemy[ENEMYBMPMAX]; // 敵用テクスチャ
・
・
・
//============================================================================= // ゲーム処理関係の自作関数群 // Copyright NKC Game Staff(←自分の名前) //----------------------------------------------------------------------------- ・ ・ ・ // グローバル変数 /* 自ソースでのみ利用するもの */ //---- ステージ別情報 static int gl_StageNo; // ステージ番号管理 //---- 背景 static TLVERTX BackVertex[4]; // 頂点情報配列 //---- 自機 static STATUS MyChara; // 自キャラステータス情報 static STATUS MyShot; // 自弾ステータス情報 //---- 敵 static STATUS EnemyInitData[ENEMYTYPEMAX]; // 敵キャラステータス情報初期化データ static STATUS Enemy[ENEMYMAX]; // 敵キャラステータス情報 static DWORD gl_EnemyTime; // 敵キャラ出現時間 static ENEMYOUTDATA EnemyOutData[ENEMYDATAMAX];// 敵キャラ出現データ static int gl_EnemyCnt; // 敵キャラ出現データのカウント static char* szEnemyOutData[] = {"", "Enemy1.dat", "Enemy2.dat", "Enemy3.dat"}; // 敵キャラ出現データファイル名 ・ ・ ・ //----------------------------------------------------------------------------- // 関数名 : GameStageInit() // 機能概要: ゲーム画面ステージ別初期化処理 //----------------------------------------------------------------------------- void GameStageInit(void) { FILE *fp; char buff[80]; DWORD time; int type; int i; //--------------------------------------------------- 各変数の初期化 // ステージ別に使用するテクスチャの作成 CreateGameStageTexture(gl_StageNo); // ポリゴンの初期化 /* 自キャラ */ InitVertex(MyChara.Vertex, 272.0f, 380.0f, 368.0f, 476.0f, 255); // 頂点データ SetRect(&MyChara.HitRect, 10, 10, 10, 10); // 当たり判定矩形 MyChara.MoveX = 2.0f; MyChara.MoveY = 2.0f; /* 自弾 */ SetRect(&MyShot.HitRect, 2, 2, 2, 2); // 当たり判定矩形 MyShot.MoveX = 0.0f; // 移動量(X方向) MyShot.MoveY = -2.0f; // 移動量(Y方向) MyShot.life = DEAD; // フラグ /* 敵キャラ出現データのカウント */ ・ ・ ・ }
・
・
・
// プロトタイプ宣言
/* 自ソース(Game.cpp)内でのみ利用するもの */
static void SetEnemyInit(LPSTATUS, float, float, float, float, LONG, LONG, LONG, LONG, float, float, int, int);
// 敵キャラ発生データ初期化処理
static void SetEnemy(void); // 敵キャラ発生処理
static void SetMyShot(void); // 自弾発生処理
static void BackDraw(void); // 背景描画
static void MyCharaDraw(void); // 自機描画
static void EnemyDraw(void); // 敵キャラ描画
static void MyShotDraw(void); // 自弾描画
static void MyCharaMove(void); // 自機移動
static void EnemyMove(void); // 敵キャラ移動
static void MyShotMove(void); // 自弾移動
static void CharaHitCheck(void); // キャラクタ同士の当たり判定
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : GameFrame()
// 機能概要: スタート画面処理
//-----------------------------------------------------------------------------
void GameFrame(void)
{
//--------------------------------------------------- 前処理
SetEnemy(); // 敵キャラの出現
SetMyShot(); // 自弾の発生
//--------------------------------------------------- 描画
BackDraw(); // 背景
MyCharaDraw(); // 自機
EnemyDraw(); // 敵
MyShotDraw(); // 自弾
//--------------------------------------------------- 移動処理
MyCharaMove(); // 自機
EnemyMove(); // 敵キャラ
MyShotMove(); // 自弾
//--------------------------------------------------- 当たり判定
CharaHitCheck(); // キャラクタ同士
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : SetMyShot()
// 機能概要: 自弾発生処理
//-----------------------------------------------------------------------------
static void SetMyShot(void)
{
// スペースキーが押されていなかったら、何もしない
if ( !(gl_KeyTbl[VK_SPACE] & 0x80) ) return;
// 発射中でなければ、自キャラの位置から発射する
if ( MyShot.life == DEAD ) {
InitVertex(MyShot.Vertex, MyChara.Vertex[0].x, MyChara.Vertex[0].y - 8, MyChara.Vertex[0].x + 8, MyChara.Vertex[0].y, 255);
MyShot.life = 1;
}
}
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : MyShotDraw()
// 機能概要: 自弾描画
//-----------------------------------------------------------------------------
static void MyShotDraw(void)
{
if ( MyShot.life == DEAD ) return;
gl_lpD3ddev->SetTexture(0, gl_TXMyShot);
gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, MyShot.Vertex, sizeof(TLVERTX));
}
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : MyShotMove()
// 機能概要: 自弾移動
//-----------------------------------------------------------------------------
static void MyShotMove(void)
{
if ( MyShot.life == DEAD ) return;
Move(MyShot.Vertex, MyShot.MoveX, MyShot.MoveY);
if ( MyShot.Vertex[2].y < gl_rcScreen.top ) MyShot.life = DEAD;
}
・
・
・
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : CharaHitCHeck()
// 機能概要: キャラクタ同士の当たり判定
//-----------------------------------------------------------------------------
static void CharaHitCheck(void)
{
int i;
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > DEAD ) {
/* 自キャラと敵キャラ */
if ( HitCheck2(MyChara.Vertex, MyChara.HitRect, Enemy[i].Vertex, Enemy[i].HitRect) ) {
GameRelease();
g_FrameNo = START_INIT;
}
/* 自ショットと敵キャラ */
if ( MyShot.life > DEAD ) {
if ( HitCheck2(MyShot.Vertex, MyShot.HitRect, Enemy[i].Vertex, Enemy[i].HitRect) ) {
MyShot.life = DEAD;
Enemy[i].life = DEAD;
}
}
}
}
}
・
・
・
※ここまでの修正を行い、ゲーム画面においてスペースキーを押すと弾が一発だけ発射されるかを確かめる。
スペースキーを押している間、弾が連射できるようにプログラムを修正する。スタート画面におけるカーソルの移動(08−6)と同様、そのままでは連続押しになってしまうので、発射後、一定時間内は次の弾が出ないような時間制御が必要になる。
/* キャラクタ情報構造体 */
typedef struct _STATUS {
TLVERTX Vertex[4]; // 頂点情報配列
RECT HitRect; // 当たり判定矩形情報
float MoveX, MoveY; // 移動量
int type; // タイプ
LPDIRECT3DTEXTURE8 Texture; // テクスチャ
int flg; // フラグ(表示:1 非表示:0)
DWORD timing; // タイミング
DWORD time; // 時間
} STATUS, *LPSTATUS;
//============================================================================= // ゲーム処理関係の自作関数群 // Copyright NKC Game Staff(←自分の名前) //----------------------------------------------------------------------------- #include "NKC_Common.h" // マクロの定義 #define STAGEMAX 3 // ステージ数 #define ENEMYMAX 100 // 敵キャラの最大数 //#define ENEMYTIME 1000 // 敵キャラの出現タイミング #define ENEMYDATAMAX 100 // 敵キャラデータ件数の最大 #define ENEMYDATAEND 99999 // 敵キャラデータ終了フラグ #define ENEMYTYPEMAX 5 // 敵キャラの種類の最大 #define MYSHOTMAX 10 // 自ショットの最大数 // グローバル変数 /* 自ソースでのみ利用するもの */ //---- ステージ別情報 static int gl_StageNo; // ステージ番号管理 //---- 背景 static TLVERTX BackVertex[4]; // 頂点情報配列 //---- 自機 static STATUS MyChara; // 自キャラステータス情報 static STATUS MyShot[MYSHOTMAX]; // 自弾ステータス情報 //---- 敵 static STATUS EnemyInitData[ENEMYTYPEMAX]; // 敵キャラステータス情報初期化データ static STATUS Enemy[ENEMYMAX]; // 敵キャラステータス情報 static DWORD gl_EnemyTime; // 敵キャラ出現時間 static ENEMYOUTDATA EnemyOutData[ENEMYDATAMAX];// 敵キャラ出現データ static int gl_EnemyCnt; // 敵キャラ出現データのカウント static char* szEnemyOutData[] = {"", "Enemy1.dat", "Enemy2.dat", "Enemy3.dat"}; // 敵キャラ出現データファイル名 ・ ・ ・
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : GameStageInit()
// 機能概要: ステージ開始時初期化処理
//-----------------------------------------------------------------------------
void GameStageInit(void)
{
・
・
・
//--------------------------------------------------- 各変数の初期化
// ステージ別に使用するテクスチャの作成
CreateGameStageTexture(gl_StageNo);
// ポリゴンの初期化
/* 自キャラ */
InitVertex(MyChara.Vertex, 272.0f, 380.0f, 368.0f, 476.0f, 255); // 頂点データ
SetRect(&MyChara.HitRect, 10, 10, 10, 10); // 当たり判定矩形
MyChara.MoveX = 2.0f; // 移動量(X方向)
MyChara.MoveY = 2.0f; // 移動量(Y方向)
MyChara.timing = 500; // 弾を撃つタイミング
MyChara.time = 0; // 弾を撃ったときの時間
/* 自弾 */
for ( i=0 ; i<MYSHOTMAX ; i++ ) {
SetRect(&MyShot[i].HitRect, 2, 2, 2, 2); // 当たり判定矩形
MyShot[i].MoveX = 0.0f; // 移動量(X方向)
MyShot[i].MoveY = -2.0f; // 移動量(Y方向)
MyShot[i].life = DEAD; // フラグ
}
/* 敵キャラ出現データのカウント */
・
・
・
}
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : SetMyShot()
// 機能概要: 自弾発生処理
//-----------------------------------------------------------------------------
static void SetMyShot(void)
{
int i;
// スペースキーが押されていなかったら、何もしない
if ( !(gl_KeyTbl[VK_SPACE] & 0x80) ) {
MyChara.time = 0;
return;
}
// 弾を撃つ時間になったかどうかを調べる
if ( gl_nowTime - MyChara.time < MyChara.timing ) return;
// 発射可能な弾を調べ、発射中でなければ、自キャラの位置から発射する
for ( i=0 ; i<MYSHOTMAX ; i++ ) {
if ( MyShot[i].life == DEAD ) {
InitVertex(MyShot[i].Vertex, MyChara.Vertex[0].x, MyChara.Vertex[0].y - 8, MyChara.Vertex[0].x + 8, MyChara.Vertex[0].y, 255);
MyShot[i].life = 1;
MyChara.time = gl_nowTime;
return;
}
}
}
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : MyShotDraw()
// 機能概要: 自弾描画
//-----------------------------------------------------------------------------
static void MyShotDraw(void)
{
int i;
gl_lpD3ddev->SetTexture(0, gl_TXMyShot);
for ( i=0 ; i<MYSHOTMAX ; i++ ) {
if ( MyShot[i].life > DEAD ) gl_lpD3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, MyShot[i].Vertex, sizeof(TLVERTX));
}
}
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : MyShotMove()
// 機能概要: 自弾移動
//-----------------------------------------------------------------------------
static void MyShotMove(void)
{
int i;
for ( i=0 ; i<MYSHOTMAX ; i++ ) {
if ( MyShot[i].life > DEAD ) {
Move(MyShot[i].Vertex, MyShot[i].MoveX, MyShot[i].MoveY);
if ( MyShot[i].Vertex[2].y < gl_rcScreen.top ) MyShot[i].life = DEAD;
}
}
}
・
・
・
//-----------------------------------------------------------------------------
// 関数名 : CharaHitCHeck()
// 機能概要: キャラクタ同士の当たり判定
//-----------------------------------------------------------------------------
static void CharaHitCheck(void)
{
int i, j;
for ( i=0 ; i<ENEMYMAX ; i++ ) {
if ( Enemy[i].life > DEAD ) {
/* 自キャラと敵キャラ */
if ( HitCheck2(MyChara.Vertex, MyChara.HitRect, Enemy[i].Vertex, Enemy[i].HitRect) ) {
GameRelease();
g_FrameNo = START_INIT;
}
/* 自ショットと敵キャラ */
for ( j=0 ; j<MYSHOTMAX ; j++ ) {
if ( MyShot[j].life > DEAD ) {
if ( HitCheck2(MyShot[j].Vertex, MyShot[j].HitRect, Enemy[i].Vertex, Enemy[i].HitRect) ) {
MyShot[j].life = DEAD;
Enemy[i].life = DEAD;
}
}
}
}
}
}
※ここまでの修正を行い、弾が0.5秒おきに一発ずつ、最大10発が撃てることを確認する。また、連射にも対応していることを確認する。
| BACK(タイプ別にキャラクタ画像を変える) | NEXT(敵キャラから弾を出す) |