この章では、ゲーム・アプリケーションの元となるウィンドウについて復習する。
まずは元となるスケルトンプログラムを準備する。方法は次のとおり。
スケルトンプログラムが正常に動くことが確認できたら、ESCキーを押したときにもアプリケーションが終了できるよう、WinProc関数を次のように修正しておく。
//-------------------------------------------------------------------------------------------------
// ウィンドウプロシジャ関数(WindowProcedure)
// メッセージ処理を行う
//-------------------------------------------------------------------------------------------------
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_KEYDOWN: // キーを押したとき
switch (wParam) {
case VK_ESCAPE:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
break;
case WM_DESTROY: // 閉じるボタンをクリックした時
PostQuitMessage(0); // WM_QUITメッセージを発行
break;
default: // 上記以外のメッセージはWindowsへ処理を任せる
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
修正後、ビルドを行い、ESCキーを押してアプリケーションが終了する(ウィンドウが閉じる)かどうか確認する。
また、マウスを必要としないゲームの場合、マウスカーソルを表示しないのが一般的である。また、マウスを使う場合でも、ウィンドウズ標準のマウスカーソルを使うことはほとんどない。
ゲーム中にマウスカーソルを表示しないようにするには、ウィンドウズのAPI関数を使って次のように行う。
//-------------------------------------------------------------------------------------------------
// ウィンドウプロシジャ関数(WindowProcedure)
// メッセージ処理を行う
//-------------------------------------------------------------------------------------------------
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_KEYDOWN: // キーを押したとき
switch (wParam) {
case VK_ESCAPE:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
break;
case WM_SETCURSOR: // カーソルの設定
SetCursor(NULL);
break;
case WM_DESTROY: // 閉じるボタンをクリックした時
PostQuitMessage(0); // WM_QUITメッセージを発行
break;
default: // 上記以外のメッセージはWindowsへ処理を任せる
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
ただし、ウィンドウ・モードの場合は、ウィンドウを移動したり、閉じるボタンをクリックするなどの場合にマウスカーソルが必要な場合もある。慎重に判断しよう。
既に説明したとおり、Windowsではアプリケーションがウィンドウ単位で管理される。また、キーボードやマウスなどを使った入力があった場合も、ウィンドウを基準にしてWindowsから各アプリケーション(ウィンドウ)に振り分けられる。
Windowsがこのような仕組みになっているため、Windowsアプリケーションは一般的に、少なくともWinMain関数とWinProc関数の2つを持っていなければならない。

WinMain関数は、アプリケーションが起動したときに最初に呼び出される関数(C言語のmain関数と同じ)で、この関数の中にはウィンドウの生成やメインループといった処理を記述するのが一般的である。
WinProc関数は、ユーザからの入力やタイマーの呼び出しといったメッセージ(イベント)に対応する処理を行うための関数である。押されたキー別に処理を記述するといったプログラムを記述できるが、同じキーでもゲームのシーンによってやりたいことが変わると思われるため、この授業ではこの関数内にゲームに関する処理は記述しないことにする。
Windowsアプリケーションでウィンドウを生成するには、まず、WNDCLASSEX構造体変数にウィンドウの属性値を設定し、それを使ってWindowsに「ウィンドウクラス」を登録する。
ウィンドウクラスとは特定の属性を持ったウィンドウのひな形のことで、実際のウィンドウはこのひな形を元に生成される。

DirectXを利用するアプリケーションでは、次のような属性値をWNDCLASSEX構造体に設定する。
WNDCLASSEX wc; // ウィンドウクラス構造体 // ウィンドウクラスを定義する wc.cbSize = sizeof(WNDCLASSEX); // WNDCLASSEX構造体のサイズを設定 wc.style = NULL; // ウィンドウスタイル(デフォルト) wc.lpfnWndProc = WinProc; // ウィンドウ関数 wc.cbClsExtra = 0; // 通常は使わない(0にしておく) wc.cbWndExtra = 0; // 通常は使わない(0にしておく) wc.hInstance = hThisInst; // このインスタンスへのハンドル wc.hIcon = NULL; // ラージアイコン(なし) wc.hCursor = LoadCursor(NULL, IDC_ARROW); // カーソルスタイル wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // ウィンドウの背景(黒) wc.lpszMenuName = NULL; // メニュー(なし) wc.lpszClassName = szWinName; // ウィンドウクラス名 wc.hIconSm = NULL; // スモールアイコン(なし)
属性を設定したWNDCLASSEX構造体変数を使ってウィンドウクラスをWindowsに登録するには、RegisterClassEx関数の引数に構造体変数のアドレスを指定して実行する。
// ウィンドウクラスの登録
if (!RegisterClassEx(&wc)) {
return (FALSE); // 登録失敗
}
そして、登録したウィンドウクラスを元にウィンドウを生成するには、CreateWindow関数を使用する。ただし、DirectX Graphicsを使うプログラムでは、ウィンドウ・モードを使うかフルスクリーン・モードを使うかによってウィンドウの生成方法を変えなければならない。
ウィンドウの生成方法の変え方は、次ページ以降で紹介する。
| NEXT(フルスクリーン・モード用のウィンドウを生成する) |