Physicsアドオン(Fusion 2.0用)
このアドオンはFusion 2.0.x用です。Fusion 2.1.xではサポートされません。(2.1用のアドオン)
概要
Physicsアドオンには、Rigidbody/Rigidbody2Dコンポーネントの同期とクライアントサイド予測に必要なコンポーネントが含まれています。
ダウンロード
| Version | Release Date | Download |
|---|---|---|
| 2.0.3 | 3月 03, 2025 | Fusion Physics 2.0.3 |
| 2.0.2 | Fusion Physics 2.0.2 | |
| 2.0.1 | Fusion Physics 2.0.1 |
主要コンポーネント
NetworkRigidbody3D:状態権限者のRigidbodyの状態を、他のピアに同期します。NetworkRigidbody2D:状態権限者のRigidbody2Dの状態を、他のピアに同期します。RunnerSimulatePhysics3D:NetworkRunnerゲームオブジェクトに任意で追加するコンポーネントで、Fusionの3D物理シミュレーションを処理します。RunnerSimulatePhysics2D:NetworkRunnerゲームオブジェクトに任意で追加するコンポーネントで、Fusionの2D物理シミュレーションを処理します。
Client Physics Simulation
RunnerPhysicsSimulate2D/RunnerPhysicsSimulate3Dは、クライアント上のシミュレーションを制御します。
⚠️ ホスト/サーバーモードにおいて、サーバーは常に物理をシミュレートします。
クライアント上の物理シミュレーションを制御するオプションは次の通りです。
- Disabled: クライアント上で物理シミュレーションは実行されず、Unityの物理エンジンで
transformも同期されません。 - SyncTransforms: すべてのティックで
UnityEngine.Physics.SyncTransform()が呼び出されます。 - SimulateForward: 再シミュレーションティックでは
UnityEngine.Physics.SyncTransform()が呼び出され、フォワードティックではUnityEngine.Physics.Simulate()が呼び出されます。 - SimulateAlways: すべてのティックで
UnityEngine.Physics.Simulate()が呼び出されます。
共有モードでは、再シミュレーションが行われないため、SimulateForwardとSimulateAlwaysの挙動は同じになります。
Disabled
リモート時間にあるオブジェクトが、ローカルでスムーズに補間されます。最も軽量なオプションですが、クライアント上のオブジェクトは、実質的に非物理かつインタラクション不可能です。SyncTransfroms()は呼び出されず、Unityの物理エンジン内でRigidbodyが移動しないため、レイキャストなどの対象にもなりません。
Sync Transforms
リモート時間にあるオブジェクトが、ローカルでスムーズに補間されます。Disabledに似ていますが、各ティックでSyncTransforms()が呼び出されるため、Unityの物理エンジン内でRigidbodyが正しく移動します。Disabledより負荷は増えますが、SyncTransforms()のおかげでレイキャストなどが有効になります。
Simulate Forward
リモート時間にあるオブジェクトが、ローカルでスムーズに補間されます。フォワードティックにおいて、ローカルでUnityの物理演算を実行することで、ローカルで予測しているプレイヤーなどの衝突判定が確実に検出されます。フォワードティックでローカルの物理演算を実行するため、SyncTransformsより負荷が増えます。ローカルで予測しているプレイヤーは、オブジェクトと限定的にインタラクション可能ですが、予測中のローカル時間とリモート時間との差異により、インタラクションはスムーズに行われない可能性があります。
Simulate Always
物理シミュレーションは、再シミュレーションティックとフォワードティックの両方で実行され、オブジェクトをローカル時間で予測します。ローカルのプレイヤーと物理オブジェクト間のインタラクション精度は非常に高くなりますが、CPU負荷も最大になります。
使用方法
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
クライアント上の物理シミュレーションを制御します。詳細は、上記の概要をご覧ください。
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
- コールバック
- 既知の問題