web-dev-qa-db-ja.com

ゲーム開発のためにネットワークを介してクロックを同期する方法は?

時間ベースの要素が多いゲームを書いています。時間を使用して、ネットワークが停止し、パケットが通過していないときのプレーヤーの位置(およびパケットが受信されるまでの時間と受信されない時間)を推定します。これは、プレイヤーが方向を選択しても動きを止めることができないという意味でパックマンタイプのゲームです。そのため、システムは理にかなっています(または少なくともそう思います)。

だから私は2つの質問があります:1)ネットワークに遅延があるので、最初にゲームのクロックをどうやって同期させるのですか? 2)それらを同期せず、それらが同じであると想定しても大丈夫ですか(私のコードはタイムゾーンに依存しません)。これは、人々が時計を変えてチートするような非常に競争の激しいゲームではありません。

ゲームはJavaおよびPython(プロジェクトとしての並行開発)でプログラムされています。

10
sinθ

私はそれが間違いなくではないOKsynchornizeのクロックでシステム。ユーザーはあなたがシステム設定に触れることを期待しておらず、多くのシステムはあなたに触れさせることさえしません。

必要なのは、タイムスタンプを片側の時計から反対側の時計に変換するための相関関係を持つことだけです。一方、プレーヤーの位置を予測するために使用する場合は、この相関をかなり正確にする必要があります。たとえば、少なくとも100分の1秒までです。システムクロックは、ランダムマシン間でこれほど適切に相関されることはありません。したがって、ネットワーク帯域幅を節約するために他のメッセージに埋め込まれている [〜#〜] ntp [〜#〜] テーマのバリエーションを使用して、自分で相関を確立する必要があります。

基本的な考え方は、送信した各パケットでタイムスタンプを送信したことと、シーケンス番号と反対側から最後のパケットを受信したときのタイムスタンプです。これから、往復を計算します。たとえば、パケットQが1000で送信され、パケットPが500で受信されたと言う場合、0でパケットPを送信し、800でQを受信して​​いる場合、往復は(800-0 )-(1000-500)=300。非対称性を知る方法はないので、パケットはどちらの方向にも半分(150)ティックを取ると仮定します。そして、そのリモートタイムスタンプは、ローカルよりも1000-(800-150)= 350ティックだけ進んでいます。往復は異なります。クロックがかなり正確であると想定する場合は、相関の長期平均を使用する必要があります。

クロックにシステムクロックを使用したくないことにも注意してください。それらは途中で再同期され、トラックから外れることがあります。 clock(CLOCK_MONOTONIC) (UNIXの場合)またはGetTickCount(Windowsの場合)を使用する必要があります(現在、これらのAPIがJavaまたはPythonでどのようにラップされているかは不明です) )。


注:SO_TIMESTAMPソケットオプション(質問のコメントのott--で言及されている socket(7) を参照)は、受信するイベントループのレイテンシの影響を分離するのに役立ちます。パケット。努力する価値があるかどうかは、どれだけ精度が必要かによって異なります。

9
Jan Hudec

どのプレイヤーの時計が正しいのかどうやって分かりますか?そうではないので、基準クロックを使用してください。

NTPはここではやりすぎです-必要なのは〜1秒の精度だけです-したがって、 rdate を使用するか、または多くの クロック同期アルゴリズムの1つから何かを選択します。

方法を選択したら、各プレーヤーのマシンにその方法による時間を(システムクロックを変更せずに)取得させます。参照UTC時刻とプレーヤーのシステムクロックUTC時刻の違いは、実際のオフセットです。たとえば、時間に関連する計算を行うときはいつでもボットの動きや光線追跡の弾丸を推定するには、システム時間を取得した後でこのオフセットを考慮に入れます。 UTCを使用すると、タイムゾーンの要素がなくなります。

1
JBRWilkinson

NTPを使用したり、このためにシステムクロックに近づいたりしないでください。この要件を実際に調べると、次のニーズがあることがわかります。

  • 時間ベースのものを進めることができるように、前のフレームから経過した時間。これは、両方の速度が異なる場合、クライアントとサーバーで異なる可能性があります(たとえば、20Hz(またはそれ以外)の固定でサーバーが実行されるが、クライアントが望みの速度で実行できるクライアントが表示される場合があります)。
  • 現在のマップが開始してからの経過時間。これはゼロベースのタイマーであり(起動時にクライアントとサーバーの両方で0に初期化するだけ)、サーバーの時間は「マスター」と見なされるため、サーバーはフレームごとにこの時間の現在のビューをクライアントに送信しますそれはサーバー上で実行されます。これは、現在のサーバー時間を取得してサーバーが起動した時間を差し引くか、上記のフレームごとの時間を累積することによって取得できます。上記のクライアント側のフレームごとの時間は、任意の2つの連続したサーバーフレーム間の補間ポイントを生成するためにも使用できます。
  • 他のすべての時間が進む参照「基準時間」。これは、クライアントとサーバーの両方で同じにすることができます(ただし、すべてのゲームタイプで同じである必要はありません)。ゲーム(または現在のマップ)の開始時に初期化されますが、その後は変更されません(新しいゲームまたは新しいマップでない限り) -開始されます)。

これは単純化された概要です-私は待ち時間/ドロップされたパケットなどの問題に対処しようとはしていません-しかし、それは全体が基づいているべき基本的なフレームワークです。

最後の項目mayは必要に応じてタイムゾーンを使用しますが、システムクロックの近くに行ったり、さまざまなタイムゾーンなどの問題を気にする必要はありません。重要なことは、実際の経過時間は高分解能のゼロベースのタイマーを使用して測定されるため、時間帯の違いに完全に依存しないということです。サーバー上の実際の現在時刻を確認したいですか?経過時間を参照基準時間に追加するだけで取得できます。クライアントも同様です。

1
Maximus Minimus