通常、ゲームは、ユーザーが何もしなくても、常に新しいフレームを描画し続けます。これは通常、onIdle()呼び出しがある場合に発生します。ユーザーがボタンなどを押したとき、またはその間に散発的にゲームがウィンドウ/画面を更新する場合は、それMSGWaitForMultipleObjects
が適切なオプションです。
ただし、連続アニメーションゲームでは、通常、レンダリングスレッドでブロックしたりスリープしたりすることはできません。代わりに、最大速度でレンダリングし、スロットルとして垂直同期に依存する必要があります。その理由は、タイミング、ブロック、およびスリープがせいぜい不正確であり、最悪の場合は信頼性が低く、アニメーションに不快なアーティファクトが追加される可能性が高いためです。
通常は、フレームに属するすべてのものをグラフィックAPI(「任意のプラットフォーム」と言ったのでOpenGL)にできるだけ速くプッシュし、ワーカースレッドに信号を送って、ゲームのロジックや物理などを開始します。次に、SwapBuffersでブロックします。
すべてのタイマー、タイムアウト、およびスリープは、スケジューラーの解像度によって制限されます。これは、Windowsでは15ミリ秒です(を使用して1ミリ秒に設定できますtimeBeginPeriod
)。60fpsでは、フレームは16.666msであるため、15msのブロッキングは壊滅的ですが、1msでもかなりの時間です。より良い解像度を得るためにできることは何もありません(これはLinuxではかなり良いです)。
Sleep
、またはタイムアウトのあるブロッキング関数は、プロセスが少なくとも要求した時間だけスリープすることを保証します(実際、Posixシステムでは、割り込みが発生した場合、スリープが少なくなる可能性があります)。時間切れになるとすぐにスレッドが実行されるという保証や、その他の保証はありません。
WindowsでのSleep(0)はさらに悪いです。ドキュメントには、「スレッドは残りのタイムスライスを放棄しますが、準備はできています。準備ができたスレッドがすぐに実行されるとは限らないことに注意してください」と記載されています。現実には、ほとんどの場合は問題なく動作し、「まったくない」から5〜10ミリ秒までブロックされますが、Sleep(0)が100ミリ秒間ブロックされることもあります。これは、発生した場合の悲惨なことです。 。
使用するQueryPerformanceCounter
ことは問題を引き起こします-ただそれをしないでください。一部のシステム(最近のCPUを搭載したWindows 7)では、信頼性の高いHPETを使用しているため、問題なく動作しますが、他の多くのシステムでは、誰も説明できない、あらゆる種類の奇妙な「タイムトラベル」または「リバースタイム」効果が見られます。デバッグ。これは、これらのシステムでは、QPCの結果がCPUの周波数に依存するTSCカウンターを読み取るためです。CPU周波数は一定ではなく、マルチコア/マルチプロセッサシステムのTSC値は一貫している必要はありません。
次に、同期の問題があります。同じ周波数でティックしている場合でも、2つの別々のタイマーは必然的に非同期になります(「同じ」などがないため)。グラフィックカードには、すでに垂直同期を実行しているタイマーがあります。これを同期に使用すると、すべてが機能し、別の1つを使用すると、最終的に同期がとれなくなります。同期がとれていないと、まったく効果がない場合や、半分完成したフレームが描画される場合、または1フレーム全体がブロックされる場合などがあります。
フレームが欠落していることは通常それほど大きな問題ではありませんが(フレームが1つだけで、めったに発生しない場合)、この場合、そもそも完全に回避できるものです。