予測カリング
イントロダクション
予測カリング は、ゲームワールドでどのようなタイミングでもプレイヤーのビューが部分的であるゲームに使用します。安全に使用でき、アクティベートも簡単です。
予測カリング を使用すると、Quantumの予測およびロールバックの間CPU時間を節約できます。有効化しておくと、ローカルのユーザーに表示されている重要なエンティティのみ実行できます。ビュー外のものはサーバーによって入力が確認された後、1ティックごとに1回だけシミュレートされます。
パフォーマンスにおけるメリットはゲームによって様々ですが、多大なものであるといえます。これはプレイヤーがの数が多いと見逃してしまいがちであるがゆえに、そのようなゲームにおいて特に重要です。シミュレーションレートが30Hzであるゲームを例にとって考えてみましょう。
ゲームに確認された入力ごとに平均10ティックのロールバックが必要だとすると、ゲームシミュレーションはおよそ300Hz実行するのに十分軽くなければばりません(ロールバックを含める)。予測カリング を使用すると全フレームが常に30/60Hzの予測値でシミュレーションされるようになります。そしてカリングは予測バッファ内で実行中の予測エリアに適用されます。
予測カリングを設定する
予測カリング の結果として、予測したシミュレーションがフレームの最終結果として受け入れられることはありません。間引きされた部分があるためです。つまり、ゲームステート全体のシミュレーションを進めることはないのです。
予測カリングをセットアップするには、2つの手順があります。1つはQuantumで、もう1つはUnityでおこなう手順です。
Quantumでおこなう手順
Enabling prediction culling in Quantum is a simple as adding the culling systems to SystemSetup.cs
before any of the other systems.
Quantumでの予測カリングの有効化は、他のすべてのシステムよりも前にカリングシステムをSystemSetup.cs
に追加するだけでおこなえます。
C#
namespace Quantum {
public static class SystemSetup {
public static SystemBase[] CreateSystems(RuntimeConfig gameConfig, SimulationConfig simulationConfig) {
return new SystemBase[] {
// pre-defined core systems
new Core.CullingSystem2D(),
new Core.CullingSystem3D(),
new Core.PhysicsSystem2D(),
new Core.PhysicsSystem3D(),
new Core.NavigationSystem(),
new Core.EntityPrototypeSystem(),
// user systems go here
};
}
}
}
デフォルトでCore.CullingSystem2D()
とCore.CullingSystem3D()
はともにSystemSetup
に含まれています。
Unityでおこなう手順
Unityでは、予測エリアを設定する必要があります。これは、予測からどのエンティティをカリングするかを決定するために使用されます。
すべてのUnityアップデートでSetPredictionArea()
を呼ぶことで、予測エリアをアップデートできます:
C#
// center is either FPVector2 or FPVector3
// radius is an FP
QuantumRunner.Default.Game.SetPredictionArea(center, radius);
予測すべき事項
物理およびNavmeshエージェント
物理エンジンとNavMesh関連のシステムは 予測カリング に影響されます。
予測カリング が有効化されている場合、認証されていない(予測された)フレーム上の目に見えるエリア内のエンティティのみ考慮に入れてアップデートされるようになります。
物理とNavmesh関連のエージェントが、関連コンポーネント(PhysicsCollider、 PhysicsBody、NavMeshPathFinder、NavMeshSteeringAgent、 NavMeshAvoidanceAgent)を持つエンティティの更新をスキップし、ローカルマシン上の予測領域の中心点と半径で定義された関心領域外のエンティティの更新をスキップすることで、CPU サイクルが節約されます。
イテレーター
独自のコードにも 予測カリング のメリットがあります。Transform2D
またはTransform3D
を含むすべてのフィルターはその位置に基づいてカリングされるようになります。
本質的に、予測フレームの実行中はいつでも以下のメソッドのどれを呼び出しても予測半径の制限内のエンティティを返すのみとなります。これらのメソッドは、有力確認が到着した後で認証されたフレームをシミュレーションしている場合にはアクティブなインスタンス全てを返します。
f.Filter()
f.Unsafe.FilterStruct()
注意: 予測カリング のメリットは フィルター にはありますが、コンポーネントイテレーター には ありません。
f.GetComponentIterator()
f.Unsafe.GetComponentBlockIterator()
手動カリングコントロールフラグ
Frameで提供されるAPIを使用し、予測フレーム上のカリングを行うエンティティを手動で フラグ することもできます。
メソッド | 説明 | |
---|---|---|
SetCullable(EntityRef entityRef, bool cullable) | エンティティをカリングできるかどうかを設定する。エンティティが存在しない場合は何もおこなわない(無効なエンティティ参照も含む)。 | |
IsCulled(EntityRef entityRef) | boolを返す
True = フレームステートに関わらず、Entityがカリング可能でかつカリングエリア内にある False = エンティティがカリングされず、エンティティが存在しない、またはエンティティ参照が無効 | フレームのステートに関わらず(PredictedまたはVerified)、エンティティが現在シミュレーションから可リングされているかどうか。
エンティティがカリングされている場合、または存在しない場合にはTrue(たとえば、予測領域でない場合)。 そうでない場合には、False(エンティティが存在し、カリングされていない場合)。 |
Culled(EntiyRef entityRef) | エンティティが予測カリングされるか。
フレームがPredictedされ、かつエンティティがIsCulledされる場合には、True。 そうでない場合にはFalse(フレームがVerifiedされるか、またはエンティティがカリングされない場合)。 |
|
Cull(EntiyRef entityRef) | カリング可能でかつ存在するエンティティを、このティックに手動でマークする。 | エンティティが存在しない、またはカリング可能でない場合には何もしない。 |
ClearCulledState() | そのフレーム上のすべてのエンティティのカリングステートをリセットする。 | 各フレームシミュレーションの最初で、自動的に呼び出される。 |
一貫性のあるステートを保持し、非同期を避けるには、もともとフラグしておいた、同じシステム内の認証されたフレームのカリングされたエンティティの フラグを外します 。そうすることで一貫性のあるステートが保持され、非同期を回避します。
乱数発生の問題を避ける
RNGSession インスタンスを 予測カリング と一緒に使用することは完全に安全で、決定性も保証されています。ただしこれらを組み合わせると、2つのエンティティが RNGSession を共有していた場合表示に揺れが生じることがあります。認証されたフレームがシミュレーションされた後、予測されたエンティティに新しい乱数の値が生成されたことでデフォルトのほうがQuantumの_globals_
に保存する場合などです。これは 認証された フレームがシミュレーションされた後に、予測された エンティティに新たなRNGが生成されたためです。これによってエンティティの最終的な位置が変更/修正されます。
これを解決するには分離したRNGSession構造体をカリングする各エンティティに保存することです。分離することで、ロールバックで実際に必要とならない限りカリングが予測エンティティの最終位置に影響しないようになります。
chsarp
struct SomeStruct {
RNGSession MyRNG;
}
各RNGSessionをそれぞれのシード値で、任意の方法で差し込めます。
Back to top