私はかなり単純な2Dマルチプレイヤーオーバーネットワークゲームを書いています。今のところ、安定したループを作成することはほぼ不可能だと思います。安定とは、特定の計算が行われ、厳密な期間にわたって繰り返されるような種類のループを意味します(たとえば、25ミリ秒ごとに、それが今私が戦っているものです)。私はこれまで、これを除いて多くの深刻な障害に直面していません。
このゲームでは、サーバーアプリケーションとクライアントアプリケーションの両方でいくつかのスレッドが実行され、さまざまなタスクに割り当てられています。サーバーアプリケーションのエンジンスレッドを例にとってみましょう。このスレッドでは、ゲームの計算にかかる時間を考慮して、Thread.sleepを使用してゲームループを作成しようとしています。これがrun()メソッド内に配置された私のループです。Tick()関数はループのペイロードです。これには、ゲームを定期的に更新する他のメソッドへの順序付けられた呼び出しが含まれているだけです。
long engFPS = 40;
long frameDur = 1000 / engFPS;
long lastFrameTime;
long nextFrame;
<...>
while(true)
{
lastFrameTime = System.currentTimeMillis();
nextFrame = lastFrameTime + frameDur;
Tick();
if(nextFrame - System.currentTimeMillis() > 0)
{
try
{
Thread.sleep(nextFrame - System.currentTimeMillis());
}
catch(Exception e)
{
System.err.println("TSEngine :: run :: " + e);
}
}
}
主な問題は、Thread.sleepが、どれだけスリープするかについての期待を裏切るのが大好きなことです。特にWindowsXPを搭載した一部のマシンでは、スレッドをはるかに長い時間またははるかに短い時間で簡単に停止できます(私は自分でテストしましたが、WinXPはWin7や他のOSと比較して非常に厄介な結果をもたらします)。私はインターネットをかなり調べてきましたが、結果は期待外れでした。実行しているOSのスレッドスケジューラと、いわゆる粒度のせいのようです。私が理解している限り、このスケジューラーは、一定の時間にわたって、システム内のすべてのスレッドの要求を常にチェックし、特に、スレッドをスリープ状態から復帰させます。再確認時間が1msのように短い場合、スムーズに見える場合があります。ただし、WinXPの粒度は10〜15ミリ秒と言われています。また、Javaプログラマーだけでなく、しかし、他の言語を使用している人もこの問題に直面しています。これを知っていると、安定した、頑丈で、信頼できるゲームエンジンを作ることはほとんど不可能のようです。それにもかかわらず、彼らはいたるところにいます。どういう意味でこの問題と戦ったり回避したりできるのだろうかと非常に思っています。もっと経験豊富な人が私にこれについてのヒントを教えてもらえますか?