概要
概要
Physicsアドオンには、Rigidbody
/Rigidbody2D
コンポーネントの同期とクライアントサイド予測に必要なコンポーネントが含まれています。
NetworkRigidbody3D
:状態権限者のRigidbody
の状態を、他のピアに同期しますNetworkRigidbody2D
:状態権限者のRigidbody2D
の状態を、他のピアに同期しますRunnerSimulatePhysics3D
:NetworkRunner
のゲームオブジェクトに追加されるコンポーネントで、Fusionの3D物理シミュレーションを処理しますRunnerSimulatePhysics2D
:NetworkRunner
のゲームオブジェクトに追加されるコンポーネントで、Fusionの2D物理シミュレーションを処理します
使用方法
NetworkRigidbody
コンポーネントを使用するためには、以下の手順に従ってください。
Rigidbody
が付いたプレハブ、またはシーンオブジェクトに、NetworkObject
とNetworkRigidbody3D
(2DならNetworkRigidbody2D
)を追加してください。このコンポーネントは、状態権限者のRigidbody
の状態を他のピアへ複製したり、Rigidbody
に対するクライアントサイド予測・ロールバック・再シミュレーションを処理します。NetworkRunner
プレハブに、RunnerSimulatePhysics3D
(またはRunnerSimulatePhysics2D
)を追加してください。このコンポーネントが、UnityのPhysics.Simulate()
を引き継ぐようになります。- すべてのシミュレーションコードが、
FixedUpdateNetwork()
内で実行されていることを確認してください。
Fusion 1 から Fusion 2 への移行
- IBeforePhysicsStep
/IAfterPhysicsStep
コールバックは削除され、RunnerSimulatePhysics
のコールバックに置き換えられました。後述のコールバックをご覧ください。
拡張 / 修正
NetworkRigidbody
とRunnerSimulatePhysics
コンポーネントは、多くのケースで動作するように設計されています。しかし、プロジェクト固有のニーズに合わせて、これらを修正することもできます。クラスのいくつかの仮想メンバーはオーバーライドすることができますが、コンポーネントを参考にして独自クラスを作成したり、コンポーネントを直接修正したりする方が多いかもしれません。Fusionは、これらのコンポーネントに全く依存していないため、自由に修正しても構いません。
NetworkRigidbody2D / NetworkRigidbody3D
NetworkRigidbody3D
とNetworkRigidbody2D
は、NetworkTRSP
クラスを継承しているため、すべての関心領域(AOI)処理が有効です。関心領域の仕様については、マニュアルのNetworkTRSPをご覧ください。
スケールの同期
有効にすると、transform.localScale
が同期されます。
親子関係の同期
有効にすると、transform.parent
が同期されます。Rigidbody
の親を持つRigidbody
は、キネマティックに設定されます。親子関係を設定したRigidbody
のAreaOfInterestOverride
は、自動的に親のネットワークオブジェクトに設定されます。
親子関係の同期には、いくつかの注意点があります。
- 親の
transform
には、必ずNetworkBehaviour
コンポーネントが必要です。親を見つけるために、NetworkBehaviourId
が使用されるからです。 NetworkRigidbody
は、ルートのネットワークオブジェクトにあることが必須です。(通常はそうなります)- 親の
transform
を、ネットワークオブジェクトの子のtransform
にすることができます。プレイヤーの手などが例です。
Interpolation Target
指定したtransform
が、Render()
間の補間に使用されます。これは通常、Rigidbody
の、Collider
を持たない子要素のtransform
になります。
値をnull
にすると、ルートのNetworkRigidbody
が補間に使用され、シミュレーションループ開始時にティック精度の位置が返るようになります。InterpolationTarget
の値は、実行時にコードから変更することもできます。
子要素に対してInterpolationTarget
を使用する利点は、補間によって物理演算のキャッシュがクリアされないことです。ただし、子要素のRigidbody
のスケールの同期が無効になります。
Rigidbody
で予期しない(摩擦や積み重ねの)挙動が発生することを避けるため、InterpolationTarget
はnull
にしておくことを推奨します。
InterpolationTarget
が必要なケースは、以下の通りです。
MovePosition()
を使用してキネマティックRigidbodyを動かす場合:InterpolationTarget
を使用しない場合、transform.position
とtransform.rotation
の更新によって補間が行われます。transform
を直接変更すると、Rigidbody
のMovePosition()
の呼び出しが上書きされてしまいます。- 補間の影響を受けずに物理演算を行う必要がある場合:
Transform
を直接移動させる補間は、Rigidbody
の静止摩擦やスリープモードなどに副作用を及ぼします。これはRender Sleep Thresholdsで軽減できますが、それでも許容できない干渉が発生することがあります。
InterpolationTarget
を使用する場合は、Rigidbody
に干渉しないように、指定するオブジェクトにはCollider
が含まれないことを確認してください(干渉を避けるためのInterpolationTarget
だからです)。すべてのビジュアルエフェクトは、InterpolationTarget
の方に合わせてください。
備考: スケールと親子関係の同期を同時に使用している場合、InterpolationTarget
を使用すると正しい結果になりません。ゲームオブジェクトのスケールは、その親のスケールに影響を受けるため、コードで正しく複製することはほぼ不可能です。スケールの結果を正確に得るため、InterpolationTarget
はnull
のままにしておくことを推奨します。
備考: カメラをInterpolationTarget
に追従させていないのは、よくある間違いです。カメラをInterpolationTarget
に追従させることで、カメラの移動を補間できます。
Sleep Thresholds
有効にすると、transform
の変化量が、指定したすべてのしきい値を下回った時に、ルートのtransform
の補間が行われなくなります。これによって、ルートのtransform
が移動することによる影響(物理演算のキャッシュのクリアや、スリープの解除)を軽減できます。スリープは、サーバーの権限を持つピアにとって特に重要です。オブジェクトがほんの少し動いただけでもネットワークトラフィックが発生するため、Rigidbody
をスリープさせられるようにすることで、ネットワークトラフィックが大きく減少します。
備考: Sleep Thresholdsは、InterpolationTarget
を使用していない場合のみ適用されます。
Use Render Sleep Thresholds
しきい値のチェックを有効にします。無効にすると、オブジェクトでは常に補間が行われます。
Render Thresholds
- Use Energy:
Rigidbody
の速度と角速度のエネルギーがしきい値を超えていたら、補間が行われます。 - Position:
transform
の位置の変化量がこの値を超えていたら、補間が行われます。値が0なら、テストはスキップされます。 - Rotation:
transform
の回転の変化量がこの値を超えていたら、補間が行われます。値が0なら、テストはスキップされます。 - Scale:
transform
のスケールの変化量がこの値を超えていたら、補間が行われます。値が0なら、テストはスキップされます。
Teleport()
NetworkTransform.Teleportをご覧ください。
MovingTeleport()
テレポート移動を開始します。このメソッドは、RunnerSimulatePhysics3D
/RunnerSimulatePhysics2D
で物理シミュレーションが行われる前に、FixedUpdateNetwork()
内で呼び出す必要があります。テレポートは物理シミュレーション後まで延期され、物理シミュレーション前後の位置・回転の値がキャプチャされます。これによって、正しいテレポート前からテレポート先への補間が繋がるようになります。これは標準的なTelerport()
の別バージョンで、補間が1ティック停止します。
RunnerSimulatePhysics2D / RunnerSimulatePhysics3D
NetworkRunner
プレハブに追加されるこれらのコンポーネントで、どのように物理シミュレーションを処理したいかを指定できます。コンポーネントは、適切な物理のSimulate()
を、FixedUpdateNetwork()
ごとに呼び出します。
Physics Authority
FusionがこのコンポーネントからPhysics.Simulate()
/Physics2D.Simulate()
を呼び出すようにするか、Unityの物理設定(自動またはスクリプト)のままにしておくかどうかを指定します。
Auto
を指定すると、以下のケースでFusionがSimulate()
を呼び出すようになります。
- 共有モードの以外のモードで、ゲームを実行している場合。共有モードはデフォルトで、
FixedUpdateNetwork()
外でオブジェクトを動かすことを想定しています。FixedUpdateNetwork()
内でネットコードを適用する場合、このコンポーネントを追加してPhysicsAuthority
をFusion
に設定する必要があります。 - マルチピアモードを有効にしている場合。Unityは2つ目以降の物理シーンを自動でシミュレーションしないため、マルチピアモードを使用する際には、Fusionが
Simulate()
呼び出しを制御する必要があります。
Physics Timing
Physics Authority
がFusion
の場合、物理演算の実行タイミングを指定します。
Client Physics Simulation
クライアント上の物理シミュレーションを制御します。選択肢は以下の通りです。
- Disabled: クライアント上で物理シミュレーションは実行されず、
transform
も同期されません。 - SyncTransforms: すべてのティックで
UnityEngine.Physics.SyncTransform()
が呼び出されます。 - SimulateForward: 再シミュレーションのティックでは
UnityEngine.Physics.SyncTransform()
が呼び出され、順方向のティックではUnityEngine.Physics.Simulate()
が呼び出されます。 - SimulateAlways: すべてのティックで
UnityEngine.Physics.Simulate()
が呼び出されます。
⚠️ サーバーは常に物理シミュレーションを行います。共有モードでは、順方向のティックのみでシミュレーションが行われるため、SimulateForward
とSimulateAlways
の挙動は同じになります。
DeltaTime Multiplier
物理のSimulate()
に渡される乗数値です。時間を加速させたい場合は1より大きい値を渡し、時間を遅くしたい場合は0~1の値を渡します。
Set FixedTimestep
有効にすると、UnityのFixedTimestep
の値が、FusionのDeltaTime
に一致するように設定されます。これによって、FixedUpdate
内のコードを、Fusionのティックとほぼ連動して動作させることができます。
重要: FixedUpdate()
とFixedUpdateNetwork()
が完全に連動することは決してありません。まず検討すべきなのは、これら2つの実行タイミングを同時に使用するのを避けることです。通常、FusionのすべてのシミュレーションコードはFixedUpdateNetwork()
内に記述し、共有モードでは例外として、必要に応じてUpdate()
で変更を行うことがあります。
コールバック
Fusion 2ではINetworkRunnerCallbacks.IBeforePhysicsStep
とINetworkRunnerCallbacks.IAfterPhysicsStep
が削除され、以下のように置き換えられました。
OnBeforeSimulate / OnAfterSimulate
登録されたこれらのメソッドは、RunnerSimulatePhysics
がシミュレーションを行うたびに呼び出されます。
C#
using Fusion;
using Fusion.Addons.Physics;
using UnityEngine;
public class FusionPhysicsAddonExample : NetworkBehaviour
{
private RunnerSimulatePhysics3D _physicsSimulator;
public override void Spawned()
{
// Get our RunnerSimulatorPhysics instance (this needs to be added to the Runner)
_physicsSimulator = Runner.GetComponent<RunnerSimulatePhysics3D>();
// Register callback for EVERY simulation tick
_physicsSimulator.OnBeforeSimulate += OnBeforeEverySimulate;
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
// Unregister (a good practice)
_physicsSimulator.OnBeforeSimulate -= OnBeforeEverySimulate;
}
void OnBeforeEverySimulate() {
// Implement code to execute before every Physics.Simulate
}
}
QueueBeforeSimulationCallback / QueueAfterSimulationCallback
これらのコールバックは、1度限りのコールバックとしてキューに入れられ、次にシミュレーションが行われた際にトリガーされます。
C#
using Fusion;
using Fusion.Addons.Physics;
using UnityEngine;
public class FusionPhysicsAddonExample : NetworkBehaviour
{
private RunnerSimulatePhysics3D _physicsSimulator;
public override void Spawned()
{
// Get our RunnerSimulatorPhysics instance (this needs to be added to the Runner)
_physicsSimulator = Runner.GetComponent<RunnerSimulatePhysics3D>
}
public override void FixedUpdateNetwork()
{
if (_physicsSimulator.HasSimulatedThisTick)
{
Debug.LogWarning($"Component is running FixedUpdateNetwork AFTER Physics Simulation, check my Script Exec Order");
PostSimulateActivity();
} else {
// Queue our method for a one time deferred callback
_physicsSimulator.QueueAfterSimulationCallback(PostSimulateActivity);
}
}
void PostSimulateActivity() {
// Implement code to execute after specific Physics.Simulate calls
}
}
既知の問題
- 子
Rigidbody
の物理挙動は(キネマティックに設定されていても)予測困難で、Rigidbody
がシミュレーション前の位置にあったかのような形で、オブジェクトと衝突することがあります。そのため子要素は、Collider
を無効にし、コリジョンには依存させないことを推奨します。 - 子要素のスケールは、
InterpolationTarget
を持たないすべての親要素に依存します。子要素のスケーリングとInterpolationTarget
を組み合わせて使用したい場合は、InterpolationTarget
をルートから切り離し、親子関係を再設定する独自のコードを記述する必要があります。基本的には、すべてのRigidbody
のCollider
/Transform
階層(InterpolationTarget
を含む)のコピーを作成します。 MovePosition()
とMoveRotation()
は、InterpolationTarget
を使用する必要があります。ただし、transform.position
/transform.rotation
の値を直接設定して、キネマティックRigidbody
を動かすなら、その必要はありません。
- 概要
- 使用方法
- Fusion 1 から Fusion 2 への移行
- 拡張 / 修正
- NetworkRigidbody2D / NetworkRigidbody3D
- スケールの同期
- 親子関係の同期
- Interpolation Target
- Sleep Thresholds
- Use Render Sleep Thresholds
- Render Thresholds
- Teleport()
- MovingTeleport()
- RunnerSimulatePhysics2D / RunnerSimulatePhysics3D
- Physics Authority
- Physics Timing
- Client Physics Simulation
- DeltaTime Multiplier
- Set FixedTimestep
- コールバック
- 既知の問題