タイムフレームと時間
マルチプレイヤーゲームにおける時間
ネットワークにおける時間はしばしば混乱を招くものであり、把握するのが非常に難しいことがあります。「真の」時間というものはほとんど存在せず、むしろ相対的な時間や、それに伴う時間のパラドックスが存在し、ゲーム製作者はそれをどのように解決または隠すかを決定しなければなりません。
オンラインマルチプレイヤーゲームの全ての複雑性の根源となる主な要素はネットワーク遅延です。プレイヤー同士は他のプレイヤーの過去についてのみ知ることができます。
この遅延のために存在する主なタイムフレームは2つです:
- リモートタイムフレーム
- ローカルタイムフレーム
承知しました。それでは、翻訳を修正いたします。
リモートタイムフレーム
リモートタイムフレームは、サーバーからクライアントに到達したティック(およびそれに関連するオブジェクトの状態)を説明します。このタイムフレームは、最も最近確認された過去の状態です。
このタイムフレームはクライアントのみに存在し、それ自体は特定の「時間」ではなく、むしろ最近確認されたサーバーの状態のより一般的な説明です。
注意:サーバーにはリモートタイムフレームは存在しません - サーバーの唯一のタイムフレームはローカルです。
ローカルタイムフレーム
ローカルタイムフレームは、すべてのシミュレーションが完了した後、オブジェクトがローカルに存在する状態を説明します(適用可能な場合は再シミュレーションや予測も含みます)。クライアントではこれを予測された状態とも呼びます。サーバー/ホストにはこれが唯一存在するタイムフレームです。
クライアントはサーバーよりも先行して存在する必要があります。そうすることで、クライアントはサーバーに入力(サーバーモードの場合)や状態(共有モードの場合)を提供することができます。その後、サーバーは関連するティックをシミュレーションします。したがって、クライアントのローカルタイムフレームは常にリモートタイムフレームよりも先行しています。
ネットワークオブジェクトが前方シミュレーションの後に存在する状態。このタイムフレームは、オブジェクトがシミュレーションの一部である場合(Object.IsInSimulation == true)にのみ存在します。
リモート/ローカルの不一致を隠す
クライアントは、これらのタイムフレームの違いとそれによって生じるパラドックスを隠すための2つの主要なメカニズムを持っています:
予測: すべてのオブジェクトはローカルタイムフレーム(予測)に外挿されます。これにより、すべてのネットワークオブジェクトはサーバーでそのティックに存在する状態に常に概ね整合されます。避けられないエラーは、和解と再シミュレーションを通じて常に修正されます。予測についての詳細はこちらをご覧ください。
ラグ補償: Fusionには、タイムフレーム間のクエリ(レイキャストなど)を可能にする遅延補償システムが組み込まれています。遅延補償により、プレイヤーはリモートタイムフレームにあるオブジェクトと相互作用することができ、その後、サーバーがこれらのクエリを再現する際にリモートタイムフレームでのオブジェクトの描画を考慮することに依存します。この結果、サーバーはプレイヤーの入力をシミュレーションする際に過去に対してクエリを実行し、プレイヤーがその時世界をどのように見ていたかを考慮します。Fusionのラグ補償システムの詳細についてはこちらをご覧ください。
例題:テニス
私たちが解決しようとしている時間のパラドックスの簡単な例は、2人でプレイするテニスゲームです。
あなたはプレイヤー1として相手にボールを打ちます。あなたはボールが相手に届くのを見ますが、相手が以下のいずれの行動を取るかを知るには100ミリ秒待たなければなりません:
- スイングしてボールを返す
- スイングして外す
- そもそもスイングしない
プレイヤー1に何を見せますか?
ここでは相手を正確に予測することはできません。なぜなら、彼らの可能な行動はすべて非常に異なる結果を生むからですが、ボールへの反応が遅すぎて把握できないのです。
この例では、サーバー/クライアントモード を想定しており、共有モード ではありません。この問題は Shared Mode で解決するのがさらに難しいのです。
解決策 1: 予測なし
この方法は最も簡単ですが、最も悪いユーザー体験を提供します。この場合、すべてのオブジェクトがリモートタイムフレームで表示されます - 入力権限(ローカルプレイヤーオブジェクト)を含めて。
| Object | Predicted | Render |
|---|---|---|
| Local Player | No | Remote Timeframe |
| Ball | No | Remote Timeframe |
| Opponent | No | Remote Timeframe |


プレイヤーはサーバーに入力を送信しますが、サーバーの状態変更が到着するまではローカルでのみ移動します。これにより、すべてのクライアントで100%正確かつ一貫した結果が得られますが、ホスト以外のすべてのプレイヤーに対して受け入れがたい入力遅延が発生します。
注意: 入力遅延をゲームメカニクスでマスクするために機能するバリエーションを作成することも可能です。たとえば、スイングには準備動作が必要で、プレイヤーは実際のストロークが行われる150ms前にスイングを開始しなければならないといった方法です。プレイヤーのスイング入力はすぐにサーバーに送信され、ローカルプレイヤーでスイングが実行される頃にはサーバーからの確認済みのヒットが到着します。ただし、これは簡単な解決策ではなく、往復時間(RTT)は変動するため、カスタム予測と修正を用いる必要があるでしょう。
解決策 2: 完全予測
前の解決策とは逆に、ここではすべてを予測しようとします。予測についての詳細はこちらをご覧ください。
予測の利点は、プレイヤーが入力に対して即座に結果を得られ、すべてのオブジェクトが同じタイムフレーム内にあり、したがって時間的に整合していることです。しかし、この方程式には非常に重要な部分があり、これを正確に予測することはできません - 相手の入力です。
| Object | Predicted | Render |
|---|---|---|
| Local Player | Yes | Local Timeframe |
| Ball | Yes | Local Timeframe |
| Opponent | Yes | Local Timeframe |


承知しました。それでは、翻訳を修正いたします。
解決策 3: ラグ補償
これは、このパラドックスに対処するための初めての混合時間アプローチにつながります。この場合、相手とボールは予測エラーの問題を避けるためにリモートタイムフレームに保持されますが、ローカルプレイヤーはローカルタイムフレームに留まります。しかし、この時間の混合により、ローカルプレイヤーは現在のティックのために、サーバーや他のクライアントの世界とは一致しない世界を見ていることになります。ラグ補償により、プレイヤーはリモートタイムフレームにあるオブジェクトのヒットボックスと、ローカルタイムフレームにいるかのようにクエリ(レイキャストなど)を使用して相互作用することができます。サーバーは、クエリが行われた時にプレイヤーがそれらをどのように見ていたかに基づいてヒットボックスの状態を巻き戻すことで、各ティックをシミュレーションする際にこれを考慮することができます。
Fusionのラグ補償システムについての詳細はこちらをご覧ください。
| Object | Predicted | Render |
|---|---|---|
| Local Player | Yes | Local Timeframe |
| Ball | No | Remote Timeframe |
| Opponent | No | リモートタイムフレーム |
この問題が引き起こすのは、ローカルプレイヤーがボールをヒットしようとしたとき、そのボールがサーバーで実際にある場所ではなくなっているということです。ローカルプレイヤーでは、その予測によりプレイヤーがボールをヒットする結果になります。しかし、サーバーでは、プレイヤーがスイングしたティックが到着した際、サーバーはボールがプレイヤーを既に通り過ぎていると認識します。サーバーはそのミスを既にシミュレーションしており、ボールはプレイヤーのはるか先に進んだ状態で、すでに次のティックをすべてのクライアントに送信しています。
ラグ補償を使用すれば、サーバーはプレイヤーがスイングした時に彼らが見たボールのヒットボックスを巻き戻すことができ、過去にボールを実際にヒットした場合の位置に大幅に補正することができます。しかし、そうなるとボールに対して大きくて衝撃的な補正がかかることになります。このため、ここではラグ補償は役に立ちません。
解決策 4: タイムフレームシフト
これは、このパラドックスに対処するための第二の混合時間アプローチにつながります。この場合、相手は予測エラーの問題を避けるためにリモートタイムフレームに保持され、ローカルプレイヤーはローカルタイムフレームに留まります。ボールはローカルタイムフレームに予測されますが、ローカルタイムフレームとリモートタイムフレームのブレンドでレンダリングされます。ボールがローカルプレイヤーの近くにあるときは、ローカルタイムフレームでレンダリングされ、予測された位置を示します。ボールが相手に近づくと、リモートタイムフレームでレンダリングされます。二つの間を移動する際は、一方のタイムフレームから他方のタイムフレームへと線形補間(lerp)されます。
| Object | Predicted | Render |
|---|---|---|
| Local Player | Yes | Local |
| Ball | Yes | Variable based on distance |
| Opponent | No | Remote |


ボールは予測されているため、スイングする際にローカルプレイヤーのティックの正しい位置にあります。ボールの予測は、相手の近くにいるときには間違っており(予測された相手は古い位置にいて、スイングしない)、そのエラーは相手の状態が到着した際に再シミュレーション中に修正されます。しかし、ボールはこの予測をレンダリングしていないため(リモートタイムフレームでボールをレンダリングしている)、すべてのミスした予測はプレイヤーには見えません。
この場合の結果としてのアーティファクトは、ボールが相手に向かって実際のスピードよりも遅い速度で移動しているように見え、ボールがプレイヤーに向かってはより速い見かけの速度で迫ってくることになります。これはレンダー時間のシフトによるものです。
シミュレーション vs レンダリング
シミュレーションとレンダリングの違いを理解するためのもう一つの重要な時間の概念です。
シミュレーション:定期的な間隔で(
Runner.DeltaTime、これは1f / TickRateに相当)、Fusionはシミュレーションに参加しているすべてのネットワークビヘイビアに対してFixedUpdateNetwork()を呼び出します。シミュレーション後のすべてのネットワークビヘイビアの状態はキャプチャされ、これをスナップショットと呼びます。これらのスナップショットはキーフレームとして考えることができます。レンダリング:Unityの画面リフレッシュは、シミュレーションの間隔と非常にまれにしか一致しません。Unityの各アップデートでシミュレーションの最新の結果をユーザーに提示すると、特に移動の場合に非常に引っかかる結果になります。補間は、この問題を解決し、常に2つの以前のシミュレーションされたフレーム間を補間します。




ローカルタイムフレームとリモートタイムフレーム
マルチプレイヤーゲームの開発は、主に遅延やロスによって引き起こされる問題を解決することに関わっています。遅延のために、真の単一の時間は存在しません。すべての時間が相対的になり、これらの相対的な時間をタイムフレームと呼びます。具体的には、ローカルタイムフレームとリモートタイムフレームです:
- リモートタイムフレーム:このタイムフレームはクライアントにのみ存在し、受信したサーバーの状態を表します。これは特定の時間ではなく、最近確認されたサーバーの状態に関するより一般的な説明です。注意:サーバーにはリモートタイムフレームは存在しません - 唯一のタイムフレームはローカルです。
- ローカルタイムフレーム:ネットワークオブジェクトが前方シミュレーションの後に存在する状態です。このタイムフレームは、オブジェクトがシミュレーションの一部である場合にのみ存在します(
Object.IsInSimulation == true)。
どのタイムフレームをプレイヤーに提示するかは、ゲーム開発者の裁量に委ねられています。最良の体験を生み出すために。
ネットワークにおける主な時間のパラドックスは、プレイヤーに自分の入力と行動に対して即時感を与える必要から生じます。プレイヤーがボタンを押したり、ジョイスティックを動かしたりすると、期待されるのは即座の反応です。
基本的なサーバークライアントアーキテクチャでは、予測がない場合、プレイヤーはキーを押し、そのキー入力がサーバーに送信されます。サーバーはそのキー入力に応じてゲームシミュレーションの状態を変更し、すべてのプレイヤーに最新のゲーム状態を送信します。これにより、すべてのプレイヤーが物事の状態について完全に一致する結果になります。
しかし、これでは膨大な入力遅延が発生し、ほとんどのゲームでは受け入れられません。この遅延を隠すために、ほとんどのネットワークアーキテクチャは、予測またはラグ補償を使用します。
ただし、ネットワークでは、すべてのネットワークエンティティの状態の真実の源(状態の権限)が常に1つのピアのみです。その権威あるピアがローカルプレイヤーのピアでない場合、予測を行う必要があります。
サーバーモードとタイムフレーム
サーバーモードおよびホストモードにおいて、クライアントは予測された可能な未来(ローカルタイムフレーム)に存在するものと考えられます。そして、クライアントはサーバースナップショットが過去のティックに対して到着するまで、オブジェクトの真の状態を知ることはできません(リモートタイムフレーム)。
プレイヤーの入力は毎ティック記録され、サーバーに送信され、その入力はそのティックのシミュレーションでサーバーによって使用されます。
サーバークライアントモード(サーバー/ホスト/シングル)では、サーバーはすべてのネットワークオブジェクトの状態の権限を持っています。したがって、予測されていないローカルタイムフレームを持つ唯一のピアであり、真の現在に存在する唯一のピアです。サーバーがFixedUpdateNetwork()内でネットワークオブジェクトの状態(ネットワークプロパティ)に加えるすべての変更は、権威があり、最終的なものです。
しかし、クライアントは各ティックのプレイヤー入力をサーバーに提供し、その入力がサーバーの各ティックのシミュレーションより前にサーバーに到達する必要があります。サーバーは過去を修正することができないため、あるティックに対するプレイヤー入力がそのティックのシミュレーションのために時間内にサーバーに到達しなかった場合、その入力は失われ、サーバーは以前の入力を外挿するか、そのプレイヤーのデフォルト入力値を使用しなければなりません。
このため、クライアントは未来に存在する必要があります - 各プレイヤーが各ティックの入力を収集し、それをサーバーのティックシミュレーションのかなり前に送信できるようにするためです(そのクライアントがネットワークオブジェクトを予測しているかどうかにかかわらず)。クライアントがどれだけ先に存在する必要があるかは、平均往復時間(RTT)の関数です。RTTやピングが大きいほど、必要なクライアントの予測ウィンドウも大きくなります。この予測ウィンドウは、サーバー/クライアントゲームネットワーキングにおける時間のパラドックスの主な原因であり、クライアントは自分のローカルタイムフレームにおける事物の真の状態を決して知ることができません。


この混合タイムフレームのパラドックスを隠す/解決するための2つの戦略があります。
- すべてのオブジェクトをローカルの現在に外挿する(予測)。これにより、すべてのネットワークオブジェクトは、サーバーのそのティックにおいて存在するであろう状態に常におおよそ一致します。
- ラグ補償を使用して、タイムフレームを超えた相互作用を可能にします。ラグ補償により、プレイヤーはリモートタイムフレームにあるオブジェクトと相互作用でき、サーバーはシミュレーションを実行する際にクライアントが古いネットワークオブジェクトの状態を見ていることを考慮します。
共有モードとタイムフレーム
共有モードでは、プレイヤーは現在(ローカルタイムフレーム)に存在するものと考えられ、すべてのリモートオブジェクトは過去(リモートタイムフレーム)に存在します。
共有モードは、クライアントが単なる入力権限ではなく状態権限を持つという点で、サーバー/クライアントモードの運用とは異なります。しかし、この区別は主に語義的なもので、共有モードは本質的に状態権限を入力権限の変種として扱います。
サーバーが各ティックごとにプレイヤーから入力を収集し、それを用いてシミュレーションを行うのではなく、共有モードのサーバーはプレイヤーからネットワークオブジェクトの__状態__を収集します。これは、共有モードのサーバーが自らシミュレーションを行うことができず、クライアントにシミュレーションを依存して状態変更を行うためです。
しかし、この違いはリモートとローカルタイムフレームのパラダイムを変えるものではありません。ネットワークオブジェクトに対して状態権限を持つプレイヤーは、ローカルオブジェクトに直接変更を即座に適用します。これは「予測」とは呼ばれませんが、サーバーがクライアントからの結果を受け入れるためです。
リモートオブジェクト(クライアントが状態権限を持たないネットワークオブジェクト)は相対的な過去に存在し、その状態は他のピアから来ています。
リモートタイムフレーム
リモートとは、サーバーから到着するスナップショットに関連する時間を指します。クライアント上では、これらのティックスナップショットは
ローカルタイムフレーム
サーバーモードにおけるプレイヤーオブジェクトの場合、サーバーが実際に状態権限を持ちますが、プレイヤーが入力権限を持っています。プレイヤーが移動を押すと、
- リモート開始時間
- リモート終了時間
- リモートレンダリングタイムフレーム(リモート開始とリモート終了の間の線形補間)
- ローカル開始時間
- ローカル終了時間
- ローカルレンダリングタイムフレーム
- ローカル更新時間



Last updated on
Back to top