キーボードの状態を取得する(WindowsAPI)

ゲームにおけるキーボードの状態取得の考え方

Windowsアプリケーションでは、次のようにキーの入力状態を取得していた。

  1. WindowsからWM_KEYDOWNメッセージを受け取る
  2. どのキーが押されたかをパラメータから調べる

しかしこの方法ではWinProc関数内に処理を記述しなければならないため、ゲームプログラムには不向きである(ゲームにはさまざまな場面があり、場面ごとにキーの使い方が違う場合が多いため)。そこで、メッセージを使わず、WindowsAPIを使ってキーボードの状態を取得することを考える。

WindowsAPIを使ってキーボードの状態を取得する

WindowsAPIで用意されている関数のうち、キーボードの状態を取得できる関数は次の2つである。

  1. GetAsyncKeyState関数
  2. GetKeyboardState関数

GetAsyncKeyState関数の使い方

1.引数
int型。通常は仮想キー値(VK_LEFTなど)を与える
2.戻り値
shortint型
3.機能
引数に指定されたキーを調べ、該当するキーが押されていれば、最上位ビットがON(1)の値を返す

《使用例》

if ( GetAsyncKeyState(VK_SPACE) & 0x8000 )
    //スペースキーが押されているときの処理

この関数を利用する場合、キーの状態を複数の関数で利用する場合、そのつどこの関数を実行するため、効率が悪い(かもしれない)。ゲーム・ループの最初で調べたいキーを全て調べて変数に格納し、その変数の値をほかの様々な関数で参照するという手はあるが・・・

GetKeyboardState関数の使い方

1.引数
unsigned char型の256個の要素を持つ配列(のアドレス)
2.戻り値
int型。関数呼び出しが成功すると0以外の値を返す
3.機能
キーボード上の全てのキーを調べ、押されているキーがあると、そのキーの仮想番号に対応する要素の値の先頭1ビットがON(1)になる

《使用例》

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関数を次のように修正する。

//-----------------------------------------------------------------------------
// 関数名 : 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(状態別処理の考え方とプログラム)