2 / 3 ウィンドウの作成とメインループ
ゲームプログラムの基本構造である「初期化」「メインループ」「終了処理」を理解し、ウィンドウを表示してユーザーの操作を受け付けるループを実装します。
ゲームプログラムの基本構造
一般的に、ゲームは「ユーザーが終了操作を行うまで、常に画面の更新や入力を受け付け続ける」のが特徴です。
この動作を実現するため、ゲームプログラムは以下の3つのフェーズで構成されます。
- 初期化:
ウィンドウの作成や素材の読み込みなど、起動時に1度だけ行う準備 - メインループ(ゲームループ):
終了指示があるまで、毎フレーム繰り返す処理 - 終了処理:
使用したメモリの解放やライブラリの終了など、ループを抜けた後に1度だけ行う後片付け
この骨組みに沿って、コードを段階的に組み立てていきます。
ウィンドウの設定と初期化
設定と初期化コードの追加
まず、main.cpp の WinMain 関数内で、既存の return 0; の前に設定・初期化・終了処理を追加します。+ の付いた行を加え、既存の関数と return 0; は残してください。
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
ChangeWindowMode(TRUE);
SetGraphMode(640, 480, 32);
SetMainWindowText(L"C++ Basics");
if (DxLib_Init() == -1)
return -1;
DxLib_End();
return 0;設定・初期化・終了の各関数
新しく追加した各行の役割を確認しましょう。
ChangeWindowMode(TRUE) は、全画面表示ではなく、Windowsの通常のウィンドウ形式で起動するための設定です。
SetGraphMode は、描画領域の解像度と色のビット数を設定します。幅と高さの単位はピクセルです。
SetGraphMode(640, 480, 32);640:幅480:高さ32:色のビット数
SetMainWindowText(L"C++ Basics") は、ウィンドウのタイトルバーに表示する文字列を指定します。文字列の先頭にある L は、ワイド文字列として渡す指定です。このプロジェクトでは、日本語を含まないタイトルでも付けたまま使います。
DxLib_Init() は、上記の設定に基づいて実際にウィンドウを生成し、DXライブラリの各種機能を初期化する命令です。
直後の if 文で異常を検知し、初期化に失敗した場合はreturn -1; で戻り値として -1 を返して、プログラムを直ちに中断(異常終了)させています。
DxLib_End() は、プログラム終了時にDXライブラリが確保したシステム資源を解放し、安全に終了するための関数です。
初期化直後に閉じてしまう
このコードのまま保存して実行すると、ウィンドウが一瞬だけ現れてすぐに閉じてしまいます。
初期化が成功した直後、処理が次の行の DxLib_End() へ進んで終了してしまうためです。
ウィンドウを表示し続け、ゲームを動作させるには、初期化と終了処理の間に「メインループ」を実装する必要があります。
メインループの実装
繰り返す処理を追加する
main.cpp の WinMain 内で、初期化失敗時の return -1; の後、正常終了用の DxLib_End(); の直前に、+ が付いたメインループを追加してください。
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
ChangeWindowMode(TRUE);
SetGraphMode(640, 480, 32);
SetMainWindowText(L"C++ Basics");
if (DxLib_Init() == -1)
return -1;
while (ProcessMessage() == 0 &&
CheckHitKey(KEY_INPUT_ESCAPE) == 0)
{
WaitTimer(16);
}
DxLib_End();
return 0;
}追加された while ループは、ウィンドウを正常に処理でき、かつ Escape キーが押されていない間、処理を繰り返します。
繰り返しを続ける条件
while は、丸括弧内の条件が成立している間、波括弧内を繰り返します。今回の条件を二つに分けて読みます。
| 条件 | このプログラムでの意味 |
|---|---|
ProcessMessage() == 0 | ウィンドウの処理を続けられる |
CheckHitKey(KEY_INPUT_ESCAPE) == 0 | Escapeキーが押されていない |
== は左右の値が等しいかを調べます。二つの条件をつなぐ && は「両方が成立している」を表します。片方でも成立しなくなるとループを抜け、終了処理へ進みます。
ループ内の待機
WaitTimer(16) は16ミリ秒の待機を入れます。ループが待機なしに繰り返されることを抑えるため、今回のコードでは最後に置きます。
1周にはこの待機と処理の時間がかかるので、この行だけで正確な60FPSを保証するものではありません。ここでは待機を残したまま、繰り返しと終了操作を確認します。
実行と終了の確認
変更を終えたソースコードを保存し、F5 キーで実行してください。
タイトルバーに「C++ Basics」と書かれた640×480ピクセルのウィンドウが表示されるはずです。
動作を確認したら、以下の2通りの方法で正常に終了できることを確かめてください。
- Escapeキーによる終了:
ウィンドウがアクティブな状態でキーボードのEscapeキーを押して、アプリケーションが終了することを確認します。 - 閉じるボタンによる終了:
再度起動し、ウィンドウ右上の「×」ボタンをクリックして、アプリケーションが終了することを確認します。
いずれの場合も、ループを抜けた後に DxLib_End() が様々な終了処理を行い、最終的に return 0; でアプリケーションが終了します。
- 初期化、メインループ、終了処理をコード上で指し、実行する順序を説明できる
- ウィンドウのタイトル文字列や解像度の設定を行っている個所を理解した
- Escapeキーおよび閉じるボタンの双方でアプリケーションが正常に終了した