Windowsアプリケーションでは、次のようにキーの入力状態を取得していた。
しかしこの方法ではWinProc関数内に処理を記述しなければならないため、ゲームプログラムには不向きである(ゲームにはさまざまな場面があり、場面ごとにキーの使い方が違う場合が多いため)。そこで、メッセージを使わず、WindowsAPIを使ってキーボードの状態を取得することを考える。
WindowsAPIで用意されている関数のうち、キーボードの状態を取得できる関数は次の2つである。
if ( GetAsyncKeyState(VK_SPACE) & 0x8000 )
//スペースキーが押されているときの処理
この関数を利用する場合、キーの状態を複数の関数で利用する場合、そのつどこの関数を実行するため、効率が悪い(かもしれない)。ゲーム・ループの最初で調べたいキーを全て調べて変数に格納し、その変数の値をほかの様々な関数で参照するという手はあるが・・・
BYTE KeyTbl[256];
if ( !GetKeyboardState(KeyTbl) ) // 取得できたかどうかを確認
//取得できなかった場合の処理;
GetKeyboardState関数の呼び出しが成功すると、KeyTbl配列に全てのキーの状態が格納される。どのキーが押されているかを調べるには、調べたいキーの要素の値の先頭1ビットに1が立っているかどうかを調べればよい。
例えばリターンキーが押されているかどうかは次のように調べる。
if ( KeyTbl[VK_RETURN] & 0x80 )
//リターンキーが押されているときの処理;
このやり方では調べたくないキーの情報も取得してしまうが、この関数の呼び出しはゲーム・ループの最初で一度だけ行えばよい。この講座ではGetKeyboardState関数を使ってキーボードの状態を取得することにした。
WindowsAPI関数ではなく、DirectInputを使ってキーボードの情報を取得することもできる。DirectInputはキーボードやマウス、ジョイスティックなどを制御できる関数群である。
前項で作成したプログラムに、キーボードの状態を取得する処理を追加する。ゲームメイン処理のフローチャートどおり作成するなら、ゲームメイン処理関数であるUpdateFrame関数の一番最初で状態を取得するのがいいだろう。
キーボードの状態を格納する変数(配列)を宣言する。この変数はあるとあらゆる場面(関数)で使用されるので、グローバル変数として次のように宣言する。
// グローバル変数
HWND hWnd; // ウィンドウハンドル
BOOL g_appActive = FALSE; // ウィンドウの状態
char szWinName[] = "Exer003"; // ウィンドウクラス用文字列
char szWinTitle[] = "ゲーム用にプログラムを改造する"; // ウィンドウクラス用文字列
LPDIRECT3D8 gl_lpD3d = NULL; // Direct3D8インターフェイス
LPDIRECT3DDEVICE8 gl_lpD3ddev = NULL; // Direct3DDevice8インターフェイス
D3DPRESENT_PARAMETERS gl_d3dpp; // ディスプレイパラメータ
BYTE g_FrameNo = START_INIT; // フレーム選択用
BYTE gl_KeyTbl[256]; // キーボードの状態を格納
UpdateFrame関数を次のように修正する。
//-----------------------------------------------------------------------------
// 関数名 : UpdateFrame()
// 機能概要: ゲームメイン処理
//-----------------------------------------------------------------------------
BOOL UpdateFrame(void)
{
/* 現在のキー情報を取得 */
if ( !GetKeyboardState(gl_KeyTbl) ) {
MessageBox(hWnd, "キー情報の取得に失敗", "ERROR", MB_OK);
return (FALSE);
}
/* 処理の振り分け */
switch ( g_FrameNo ) {
case START_INIT:
// スタート画面を表示する前に実行する初期化関数を実行
case START_FRAME:
// スタート画面表示処理関数を実行
break;
case GAME_INIT:
// ゲーム画面を表示する前に実行する初期化関数を実行
case GAME_FRAME:
// ゲーム画面表示処理関数を実行
break;
default:
MessageBox(hWnd, "g_FrameNoの値が例外です。", "ERROR", MB_OK);
return (FALSE);
}
/* フリップ処理 */
return (TRUE);
}
※以上の修正を行ったらビルドを行い、プログラムが正常に動くかどうかを確かめる
(一切の描画を行っていないため、見た目は何も変わらない)。
| BACK(ゲームメイン処理) | NEXT(状態別処理の考え方とプログラム) |