2011/09/16

ゲームループ

ゲームループはどこぞの教本では以下のようなコードになっている。


コンソールプログラムならこれで回し続けるのもいいと思う。
ではWin32アプリだとどうすればいいのか?
実験する前に予想を立ててみた。

Windowsアプリケーションの場合考えないといけないのは次の2点。


  • GetMessage~DispatchMessageでループを回さなければならないこと。

  • キーボード・マウス等の入力を受け付ける場合はWinProcでイベントを処理しなければならないこと。


これをソースコードで実現しようとするなら以下のような作りになるのではないかと考えた。

[cpp]
int WINAPI WinMain(...)
{
...

while( true )
{
if (GetMessage(&msg , NULL , 0 , 0 )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

input();
update();
draw();

}

}

LRESULT CALLBACK WndProc(...)
{

switch( msg )
{
...

case WM_CHAR:
input_charevent(lParam);
case WM_PAINT:
draw_paintevent(hWnd);
break;
}

return DefWindowProc(...);



}
[/cpp]

もう少しオブジェクト指向っぽく書きたいなら、イベントを振り分け管理するEventManagerクラスでも作成し、
ウィンドウを作成する場合にEventManager内に実装したウィンドウプロシージャを登録し、
EventManager.AddListener()で登録したリスナーに対してメッセージを振り分け、
Input・Update・Drawクラス内でそれぞれ処理したいイベントに対して実装でもしてやればいい。


FPSの管理



FPSを管理する場合、予想したゲームループに対してsleepで調整してやればいい。
ただし、それでは入力が完全に止まってしまうか、直前のデータしか保持できないようになるので使い勝手がよくない。
下の処理ではWaitNextFrame内で前のdrawメソッド終了から16msec経過するのを待つ。
16msec以上待機していなければ待たずに抜け出してGetMessageから再び判定を行う。
また、CPU占有率対策のためにsleep(0)を挟み込む処理を行っている予定です。

[cpp]
int WINAPI WinMain(...)
{
...

while( true )
{
if (GetMessage(&msg , NULL , 0 , 0 )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

input();
update();

if( WaitNextFrame(WAIT_16_MSEC) )
{
draw();
}

}

}
[/cpp]


ここでの課題はGetMessageかDispatchMessageの処理がどれぐらいの速度で戻ってくるのか未知数。
そのため、ここでFPS管理しようとすると処理速度が遅くなる可能性がある。