14章用のプログラムを用意した。ダウンロードしてプロジェクトを作成し、正常に動くことを確認すること。
少し複雑なプログラムであるため、以下に概要を示す。
このゲームは、縦スクロール方のシューティングである(この時点では作りかけ)。敵キャラを倒しながら、ステージ毎に出てくるボスキャラ(まだいない)を倒せばゲームクリアとなる。
ステージは3面あり、上のステージに行くほど難易度が上がる(予定)。
このプログラムは、次のように作られている。
![]()
ゲーム開始時に1度だけ初期化をする変数と、ステージが切り替わるたびに初期化する変数があるため、初期化処理関数を「GameInit()」「GameStargeInit()」の2つに分割した。
- ゲーム開始時に1度だけ行う初期化
- ・キャラクタ用サーフェイスの生成
- ・ステージ番号のセット(1面からスタート)
- ・自キャラのステータス(自キャラ画像の矩形をセットし、スコアを0、ライフを1からスタート)
- ・敵キャラの画像情報(矩形、あたり判定用矩形、得点)を種類別にセット
- ステージ別に行う初期化
- ・背景用サーフェイスの生成(ステージ毎に画像が違うため)
- ・自キャラの表示座標、移動量をセット
- ・敵キャラ情報用配列のライフをすべてDEADにセット
- ・ステージ毎に違う初期化(今のところ、未使用)
ゲーム中の処理は、次の順番で各処理を実行している。
![]()
- SetEnemy関数について
- シューティングゲームでは、基本的にゲーム開始直後は自キャラのみが動き、敵キャラはいない。その後、少しずつ敵キャラが現れてくる。この関数では、敵キャラの現れ方を制御し、現れるときにはその敵キャラのステータスを更新しなければならない。
どのように現れるかをまだ決めていないため、関数の中身は空っぽである。
ゲームオーバー、ステージクリア、ゲームクリアになった場合の処理はそれぞれ作成済みであるが、まだ敵キャラを表示させていないため、今の状態ではゲームオーバーにもステージクリアにもならない。そこで、ファンクションキーのF1からF3を押すことによってステージを切り替え、F10でスタート画面に戻るようにしてある。この処理はデバッグ用とし、削除予定である。
敵キャラのタイプとして5種類用意しているが、種類が増えるたびに移動処理などの関数が増えることを考え、敵キャラの移動に関する処理を
Enemy.cppにまとめてある。これらの関数は引数に敵キャラ構造体のアドレスを指定することにより、敵キャラ用配列を外部変数にすることなく、Game.cppから呼び出すことができる。
//----------------------------------------------------------------------------- // Enemy.cppの関数のうち、他のソースで利用される関数のプロトタイプ宣言 //----------------------------------------------------------------------------- void EnemyBltStatusInit(ENEMYBLTSTATUS *, int, int, int, int, int, int, int, int, int); void EnemyStatusInit(ENEMYSTATUS*, int); void EnemyMove(ENEMYSTATUS*);ただし、プロトタイプ宣言で構造体を利用しなければならないため、common.hを次のように改造している。
//============================================================================= // プロジェクト内で共通に読み込まれるヘッダ・ファイル //============================================================================= //----------------------------------------------------------------------------- // インクルード・ファイル //----------------------------------------------------------------------------- #include <windows.h> #include <windowsx.h> #include <stdio.h> #include <time.h> #include <ddraw.h> //----------------------------------------------------------------------------- // マクロ定義 //----------------------------------------------------------------------------- #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } #define ENEMY_MAX 100 // 敵キャラの最大数(配列の大きさ) #define ENEMYTYPE_MAX 5 // 敵キャラの種類の最大 #define DEAD 0 // 死亡時の値(lifeに使用) //----------------------------------------------------------------------------- // 構造体・列挙型 //----------------------------------------------------------------------------- /* ゲームループ状態別処理用 */ typedef enum tarFRAMENO { START_INIT, START_FRAME, GAME_INIT, GAME_STARGE_INIT, GAME_FRAME, GAME_CLEAR, GAME_OVER } FRAMENO; /* 自キャラ・ステータス情報 */ typedef struct tarMYCHARASTATUS { int x, y; // 表示座標 int move_x, move_y; // 移動量 int life; // ライフ int score; // スコア RECT rect; // 画像の矩形 RECT hitrect; // 当たり判定用の矩形 int width, height; // キャラクタの幅と高さ } MYCHARASTATUS; /* 敵キャラ・ステータス情報 */ typedef struct tarENEMYSTATUS { int type; // キャラクタ種別 int x, y; // 表示座標 int move_x, move_y; // 移動量 int life; // ライフ } ENEMYSTATUS; /* 敵キャラ画像情報 */ typedef struct tarENEMYBLTSTATUS { RECT rect; // 画像の矩形 RECT hitrect; // 当たり判定用の矩形 int width, height; // キャラクタの幅と高さ int score; // 敵キャラの得点 } ENEMYBLTSTATUS;//-----------------------------------------------------------------------------// 自作ソース用ヘッダファイル(プロトタイプ宣言)のインクルード//-----------------------------------------------------------------------------#include "myDraw.h"#include "Start.h"#include "Game.h"#include "Enemy.h"//----------------------------------------------------------------------------- // 外部変数(本体は別ソース) //----------------------------------------------------------------------------- /* DirectDrawオブジェクト関係 */ extern LPDIRECTDRAW7 g_pDD; // DirectDraw オブジェクト extern LPDIRECTDRAWSURFACE7 g_pDDSPrimary; // プライマリサーフェイス extern LPDIRECTDRAWSURFACE7 g_pDDSBack; // バックバッファ extern LPDIRECTDRAWSURFACE7 g_pDDSStr; // 文字列画像用サーフェイス extern LPDIRECTDRAWSURFACE7 g_pDDSBackImg; // 背景画像用サーフェイス extern LPDIRECTDRAWSURFACE7 g_pDDSChara; // キャラクタ画像用サーフェイス /* 共通 */ extern FRAMENO g_FrameNo; // フレーム選択用 extern BYTE KeyTbl[256]; // キー情報 extern RECT ScreenRect; // ウィンドウの矩形 extern DWORD nowTickCount; // 時間制御用※ヘッダ・ファイルはインクルードした部分に読み込まれるため、自作の構造体を使う引数を持つ関数がある場合、構造体宣言文の後にインクルードしないとエラーになる
このサンプルプログラムがどのように作られ、どのように動作しているかをしっかり理解してから次へ進むこと。