ビデオ・メモリはそれほど容量がないため、画像を多く使うゲームでは、いかに少ないビデオ・メモリで多くの画像を扱うかが問題になる。最近のノートパソコンでは、少ないビデオ・メモリを補うため、メイン・メモリの一部をビデオ・メモリとして割り当てる製品が多くなったが、
メイン・メモリ上に作成された画像データは、転送速度が遅くなるため、ビデオ・メモリのみで対応できるようにプログラムするべきである。
そこで、ステージで必要な背景画像のみをビデオ・メモリにロードし、ステージが切り替わったら、別の背景画像をロードし直すというプログラムを考える。![]()
ステージごとにロードする画像を切り替えてオフスクリーン・サーフェイスを再生するサンプルプログラムを紹介する。ダウンロードし、プロジェクトを作成後、ビルドして実行する。
このサンプルでは、ゲーム開始時は1面用の背景を表示している。背景画像はF1、F2、F3キーを押すと、それぞれ切り替わるようプログラムされている。![]()
このサンプルプログラムがどのように作られているかを解説する。
1. DirectDrawオブジェクト初期化処理
今まではDirectDrawオブジェクトの初期化処理で、「スタート画面用サーフェイス(g_pDDSStart)」「ゲーム画面背景用サーフェイス(g_pDDSGame)」「ゲーム画面キャラクタ用サーフェイス(g_pDDSChara)」と3つのオフスクリーン・サーフェイスを作成していたが、
ゲーム画面背景用サーフェイスの生成を削除した。これは、ステージ毎にゲーム画面背景用サーフェイスを生成するためである。2. ゲーム初期化処理
ゲーム初期化処理を「ゲーム開始時初期化処理(GameInit関数)」と「ステージ変更時初期化処理(GameStargeInit関数)」に分割した。これは、ゲームが最初から始まる場合と、ステージが変わる場合では初期化するべき変数の値が変わるためである。
//----------------------------------------------------------------------------- // 関数名 : GameInit() // 機能概要: ゲーム開始時初期化処理 //----------------------------------------------------------------------------- void GameInit(HWND hWnd) { //------------------------------------------------------- 各変数の初期化/* ステージ番号の初期化 */StargeNumber = 0;/* キャラクタ情報の初期化(スコア、レベルなど) */ //------------------------------------------------------- フレームナンバーセット g_FrameNo =GAME_STARGE_INIT; } //----------------------------------------------------------------------------- // 関数名 : GameStargeInit() // 機能概要: ステージ別初期化処理 //----------------------------------------------------------------------------- void GameStargeInit(HWND hWnd) { //------------------------------------------------------- 各変数の初期化 /* ステージ番号によって、ロードする背景リソースを変える */CreateGameSurface(StargeNumber);/* 自キャラ(ステージ毎に初期化するべきもの) */ StatusInit(&MyChara, 0, 0, 40, 40, 310, 230, 4, 4); /* ゴキブリ(動かない) */ StatusInit(&Goki, 64, 394, 96, 426, 400, 300, 0, 0);/* ステージ別初期化処理 */switch (StargeNumber){case 0:// 1面での初期化break;case 1:// 2面での初期化break;case 2:// 3面での初期化break;}//------------------------------------------------------- フレームナンバーセット g_FrameNo = GAME_FRAME; }GameStargeInit関数の最初で、
CreateGameSurface関数を呼び出している。この関数はmyDraw.cppに作成した関数で、引数に与えられた値に対応するリソースから、オフスクリーン・サーフェイスを生成する。CreateGameSurface関数については後で解説する。
また、ステージ別に初期化が変わる場合のため、switch文を付けておいた。3. ゲームループ処理の変更
ゲーム開始時の初期化と、ステージが切り替わる毎の初期化があるため、ゲームループ処理(WinMain.cppのUpdateFrame関数)を、次のように変更している。
//----------------------------------------------------------------------------- // 関数名 : UpdateFrame() // 機能概要: 画面更新処理 //----------------------------------------------------------------------------- static void UpdateFrame(HWND hWnd) { /* 現在のキー情報を取得 */ if (!GetKeyboardState(KeyTbl)) return; /* 処理の振り分け */ switch (g_FrameNo) { case START_INIT: StartInit(hWnd); case START_FRAME: StartFrame(hWnd); break; case GAME_INIT: GameInit(hWnd);case GAME_STARGE_INIT:GameStargeInit(hWnd);case GAME_FRAME: GameFrame(hWnd); break; default: OutputDebugString("g_FrameNoの値が例外です。\n"); } /* フリップ処理 */ g_pDDSPrimary->Flip(NULL, 0); }breakを付けないことにより、スタート画面からゲームが開始された場合は「GameInit関数」→「GameStargeInit関数」→「GameFrame関数」と流れ、ステージが切り替わったら「GameStargeInit関数」→「GameFrame関数」と流れる。
4. ステージの切り替え
本来はステージをクリアしてから切り替えを行うべきであるが、今回はサンプルのため、ファンクションキーを押したら、該当するステージに切り替わるようにした。
//----------------------------------------------------------------------------- // 関数名 : GameFrame() // 機能概要: ゲーム画面更新処理 //----------------------------------------------------------------------------- void GameFrame(HWND hWnd) { BackDraw(); // 背景描画処理 CharDraw(); // キャラクタ描画処理 CharMove(); // キャラクタ移動処理 ScreenHitCheck(); // キャラクタがゲーム画面をはみ出しているときの処理 CharHitCheck(); // キャラクタ同士の当たり判定&処理// ステージ切り替え(削除予定)if (KeyTbl[VK_F1] & 0x80) /* F1キーが押されたら、1面からスタート */{StargeNumber = 0;g_FrameNo = GAME_STARGE_INIT;return;}else if (KeyTbl[VK_F2] & 0x80) /* F2キーが押されたら、2面からスタート */{StargeNumber = 1;g_FrameNo = GAME_STARGE_INIT;return;}else if (KeyTbl[VK_F3] & 0x80) /* F3キーが押されたら、3面からスタート */{StargeNumber = 2;g_FrameNo = GAME_STARGE_INIT;return;}}g_FrameNo を GAME_STARGE_INIT に変更することにより、次のループでステージ別の初期化が行われ、ゲームが再開する。
5. ゲーム背景用サーフェイス作成処理
ステージ番号を引数にし、その引数に対応するリソースからゲーム背景用サーフェイスを生成する関数を myDraw.cpp 内に作成した。
//----------------------------------------------------------------------------- // 関数名 : CreateGameSurface() // 機能概要: ゲーム背景画像用サーフェイスを作成する //----------------------------------------------------------------------------- bool CreateGameSurface(int StargeNumber) { /* すでに生成済みの場合、一度開放する */ if (g_pDDSGame != NULL) { g_pDDSGame->Release(); g_pDDSGame = NULL; } /* ゲーム背景画像用サーフェイスを作成する */ g_pDDSGame = DDLoadBitmap(g_pDD, szGameBmp[StargeNumber], 0, 0); if (g_pDDSGame == NULL) return false; else return true; }ロードに成功すると true を、失敗すると false を返すようにしているため、本来はこの関数を実行するときは、戻り値による処理を付けるべきである。
また、ゲーム背景画像用のリソース名は、次のように宣言している。
static char szGameBmp[3][10] = { // ゲーム背景画像リソース名
"BACK1BMP", /* 1面用 */
"BACK2BMP", /* 2面用 */
"BACK3BMP" /* 3面用 */
};
キャラクタ用画像はゲーム画面でしか使わない。よって、キャラクタ画像用サーフェイスはDirectDrawオブジェクト作成時ではなく、ゲームが始まるときに作成すればよいことが分かる。キャラクタ画像用サーフェイス(g_pDDSChara)の生成を myDraw.cpp 内の「InitializeDraw関数」ではなく、Game.cpp内の「GameInit関数」で行うよう、プログラムを修正しなさい。
このプログラムでは、スタート画面背景用サーフェイスとゲーム画面背景用サーフェイスをそれぞれ定義しているため、無駄である。スタート画面背景でもゲームが面背景でも同じサーフェイスを使うことにより、オフスクリーン・サーフェイスを1つ減らすよう、プログラムを修正しなさい。