【Photon Fusion】位置の同期 基本編
はじめに
Photon Fusionでネットワークオブジェクトの位置を同期したい時は、Fusionで用意されている
NetworkTransformNetworkRigidbodyNetworkRigidbody2DNetworkCharacterControllerPrototype
のいずれかのコンポーネントを使用するのが最も簡単な方法です。正しく使用すれば大抵のケースではとてもスムーズに位置の同期が行われますが、実装や用途などによっては上手くいかないケースもいくつかあるので、その辺りの注意点などもあわせて基本的な使い方を紹介します。
確認環境
- Unity 2022.2.13f1
- Fusion SDK 1.1.8 F Build 725
コンポーネントの紹介
NetworkTransform
NetworkTransformは、ネットワークオブジェクトのTransformを同期する標準的なコンポーネントになります。このコンポーネントをネットワークオブジェクトに追加すると、位置と回転が自動的に同期されるようになります。スケールは同期されません。


Fusionのスナップショット補間(Snapshot Interpolation)機能により、デフォルトの設定では自動的に位置や回転がスムーズに補間されるようになっています。補間を有効にしつつ、一時的に補間を無効にして同期したい場合(例えば、初期化を行う時など)には、NetworkTransformに定義されている、位置や回転をテレポートして同期させるメソッドが使えるでしょう。
// var networkTransform = GetComponent<NetworkTransform>();
networkTransform.TeleportToPosition(position);
networkTransform.TeleportToRotation(rotation);
networkTransform.TeleportToPosition(position, rotation);

transform.positionを更新して位置を同期した場合

networkTransform.TeleportToPosition(position)で位置を同期した場合
NetworkRigidbody
NetworkRigidbodyは、ネットワークオブジェクトの物理的な挙動を同期できます。ネットワークオブジェクトにこのコンポーネントを追加すると、Rigidbodyの値が自動的に同期されます。


物理挙動の同期の精度を上げるために、NetworkProjectConfigのPhysics EngineはPhysics 3Dに設定しておきましょう。Unityの3D物理エンジン(PhysX)の自動的な実行を無効にした上で、物理シミュレーションがFixedUpdateNetwork()のタイミングで実行されるようになります。

NetworkRigidbody2D
NetworkRigidbody2DはNetworkRigidbodyの2D版です。ネットワークオブジェクトにこのコンポーネントを追加すると、Rigidbody2Dの値が自動的に同期されます。


物理挙動の同期の精度を上げるために、NetworkProjectConfigのPhysics EngineはPhysics 2Dに設定しておきましょう。Unityの2D物理エンジン(Box2D)の自動的な実行を無効にした上で、物理シミュレーションがFixedUpdateNetwork()のタイミングで実行されるようになります。

NetworkCharacterControllerPrototype
NetworkCharacterControllerPrototypeを使用することで、プレイヤーが操作(移動やジャンプ)するネットワークオブジェクトを手軽に同期できます。移動速度やジャンプ力などは、インスペクター上のCharacter Controller Settingsから調整できます。


// private NetworkCharacterControllerPrototype characterController;
public override void FixedUpdateNetwork() {
if (GetInput(out NetworkInputData data)) {
// 方向キーで入力された方向に移動する
characterController.Move(data.Direction);
// ジャンプボタンが押されていたらジャンプする
if (data.JumpButton) {
characterController.Jump();
}
}
}
このコンポーネントはUnity標準のCharacterControllerに依存しているので、実用面では品質や移動判定の精度などで問題になることも多いかもしれません。プロトタイピングや小規模なゲームなどで使用する分には非常に便利なので、上手く使い分けていきましょう。
また、公式のアドオン(拡張機能)として「Advanced KCC」というパッケージも用意されているので、気になる方はチェックしてみても良いでしょう。
補足や注意点など
Interpolation Targetを設定する
Fusionの同期コンポーネントのInterpolation Targetは、設定していないとなめらかな補間が行われません。未設定の場合は以下のような警告表示が出ているはずなので、特段の理由がない限りは忘れずに設定するようにしましょう。

Interpolation Targetには、空のゲームオブジェクトのTransformをアタッチするのがオススメです。Interpolation Targetに設定したTransformの値は、補間処理を行うためにFusionの同期コンポーネントから操作されるため、同じゲームオブジェクトにTransformの値を更新するような別コンポーネントが追加されていると表示がおかしくなる可能性があります。
もし、空のゲームオブジェクトが存在しなければ、ネットワークオブジェクトの子要素としてInterpolation Target用のゲームオブジェクトを新規に追加すると良いでしょう。

誤差修正の挙動を確認する
Fusionの同期コンポーネントのInterpolate Error Correctionを有効にしていると、誤差修正(Error Correction)が行われます。これにより、クライアントサイド予測(Client-Side Prediction)の予測が外れた時に発生する位置ズレがなめらかに修正されるようになります。

特に不都合がなければ有効にしたままで問題ありませんが、用途によっては意図しない挙動を起こす原因になることがあるため、誤差修正を行う必要があるかは一度確認しておきましょう。
位置や回転はワールド座標系の値が同期される
Fusionの同期コンポーネントが同期する位置や回転はワールド座標系の値になります。ローカル座標系の値を同期することはできません。
物理シミュレーション予測を設定する
NetworkRigidbodyやNetworkRigidbody2Dを使用していたり、独自にネットワーク上で物理挙動を同期している場合には、物理シミュレーション予測(Physics Prediction)を行うかどうかを検討しましょう。設定はNetworkProjectConfigのServer Physics Modeから行います。

Server Only
ホスト(サーバー)側のみで物理シミュレーションが実行されます。クライアント側では物理シミュレーションは一切実行されません。クライアントはホストの物理シミュレーションの実行結果の受信を待って表示に反映するだけの形になるので処理負荷は低いですが、クライアントの物理挙動に影響を与える入力や操作には遅延が発生してしまいます。
Client Prediction
ホスト(サーバー)側でもクライアント側でも物理シミュレーションが実行されます。物理シミュレーションの予測によって、クライアントはホストからの実行結果の受信を待たずに即時のフィードバックを得られるようになりますが、物理シーンのロールバックや再シミュレーションが行われる分だけクライアント側の処理負荷が高くなったり、クライアントの実行結果とホストの実行結果の違いによる同期ズレが目立ったりする可能性があります。
物理シミュレーションの予測を行う場合は、NetworkRigidbodyやNetworkRigidbody2Dと、物理挙動に影響を与えるNetworkBehaviourのInterpolation Data SourceをPredictedにしましょう。


物理シミュレーション予測により、クライアント側の物理挙動の遅延が軽減されている
Discussion