02.基礎知識の(5)DirectX Graphicsプログラミングの基礎で学んだとおり、ダブル・バッファリングを使って画像を描画するには、次のようにプログラムすればよい。
gl_lpD3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ZRGB(255,255,255), 0.0, 0);
gl_lpD3ddev->BeginScene();
//
// ここに描画などの処理を入れる
//
gl_lpD3ddev->EndScene();
gl_lpD3ddev->Present(NULL, NULL, NULL, NULL);
では、これらの処理をどこに組み込めばよいかを考える。
通常、ゲームは場面によって描画する画像が違う。例えばスタート画面ではタイトルやメニューを表示し、ゲーム画面ではキャラクタを表示する。
今まで作ってきたプログラムは、場面によって柔軟にプログラムが行えるよう、状態別処理を考えてプログラムされている。ということは、スタート処理用関数(StartFrame関数)や、ゲーム処理用関数(GameFrame関数)に上記プログラムを組み込めば、状態(場面)ごとに描画するものを好きなように変更できる。
//-----------------------------------------------------------------------------
// 関数名 : StartFrame()
// 機能概要: スタート画面処理
//-----------------------------------------------------------------------------
void StartFrame(void)
{
// 画面のクリア
gl_lpD3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,255,255), 0.0, 0);
// シーン開始
gl_lpD3ddev->BeginScene();
//
// ここに描画などの処理を入れる
//
// シーン終了
gl_lpD3ddev->EndScene();
// フリップ
gl_lpD3ddev->Present(NULL, NULL, NULL, NULL);
// リターンキーが押されたら、ゲーム開始
if ( gl_KeyTbl[VK_RETURN] & 0x80 ) g_FrameNo = GAME_INIT;
}
しかし、この方法には「無駄」があることが分かるだろうか?確かに状態によって描画したい画像は変わる。しかし、画面のクリアやシーンの開始/終了、フリップ処理は、どんな画像を描画しても必ず行わなければならない処理である。つまり、状態別処理で変化するのは描画する画像のみであり、他の処理はどんな場面でも同じであるということが分かる。
よって、無駄を省くには次のようにプログラムするべきである。
//-----------------------------------------------------------------------------
// 関数名 : UpdateFrame()
// 機能概要: ゲームメイン処理
//-----------------------------------------------------------------------------
BOOL UpdateFrame(void)
{
/* 現在のキー情報を取得 */
if ( !GetKeyboardState(gl_KeyTbl) ) {
MessageBox(hWnd, "キー情報の取得に失敗", "ERROR", MB_OK);
return (FALSE);
}
/* 画面のクリア */
gl_lpD3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,255,255), 0.0, 0);
/* シーン開始 */
gl_lpD3ddev->BeginScene();
/* 処理の振り分け */
switch ( g_FrameNo ) {
case START_INIT:
// スタート画面を表示する前に実行する初期化関数を実行
StartInit();
case START_FRAME:
// スタート画面表示処理関数を実行
StartFrame();
break;
case GAME_INIT:
// ゲーム画面を表示する前に実行する初期化関数を実行
case GAME_FRAME:
// ゲーム画面表示処理関数を実行
break;
default:
MessageBox(hWnd, "g_FrameNoの値が例外です。", "ERROR", MB_OK);
return (FALSE);
}
/* シーン終了 */
gl_lpD3ddev->EndScene();
/* フリップ */
gl_lpD3ddev->Present(NULL, NULL, NULL, NULL);
return (TRUE);
}
//-----------------------------------------------------------------------------
// 関数名 : StartFrame()
// 機能概要: スタート画面処理
//-----------------------------------------------------------------------------
void StartFrame(void)
{
//
// スタート処理に必要な画像の描画を行う
//
// リターンキーが押されたら、ゲーム開始
if ( gl_KeyTbl[VK_RETURN] & 0x80 ) g_FrameNo = GAME_INIT;
}
※上記修正を行い、画面が白色でクリアされるかどうかを確かめよう!!
キャラクタは本来、上下左右に動き回る。表示した画像を動かすにはゲーム・ループのたびに表示座標を変化させてやればよいことは想像できる(キャラクタの移動処理は別項で説明)。移動処理はもちろん状態別処理(StartFrame関数、GameFrame関数など)で行うが、先に教えた方法では、シーンの開始と終了の間に移動処理が入ってしまう。
シーンの開始と終了の間に描画処理以外の処理を入れなくない場合は、シーンの開始・終了はUpdateFrameではなく、状態別の処理内で描画処理を行う前後に入れればよい。
| NEXT(DirectX Graphicsでの2D表示) |