Physics Addon for Fusion 2.1
This Addon is for Fusion 2.1.x. It does not support Fusion 2.0.x.
Only for Client Host or Dedicated Server modes. For Shared Mode see Physics.
Overview
The Physics addon includes the components necessary for client-side-prediction of rigidbodies.
Fusion 2.1 comes with 2 built-in approaches for synchronizing physics via NetworkTransform. For more information see Physics.
For most use cases the built-in modes are sufficient. The client-side-prediction mode of the addon supports high precision real-time physics interactions but the resimulations of the physics step are very CPU expensive.
Download
Physics Simulation
Physics simulation is run on both resimulation and forward ticks to predict objects to local time. This gives the highest quality interaction between physics objects and local
players, but has high CPU cost due to multiple physics steps being simulated.
Core Components
NetworkRigidbody
- Synchronizes Rigidbody/Rigidbody2D state from the State Authority to other peers.RunnerPhysicsSimulate
- Component which is added to theNetworkRunner
GameObject. Allows Fusion to handle Physics Simulation.
Usage
To use the NetworkRigidbody
component follow these steps:
- Add
NetworkRigidbody
to a rigidbody/rigidbody2D prefab or scene object. This component replicates the rigidbody state from the State Authority to other peers. It also
handles reset and reconciliation of the rigidbody for client prediction re-simulation. - Add
RunnerSimulatePhysics
to yourNetworkRunner
prefab. This component takes over Unity's Physics.Simulate() calls. An instance will be automatically added to the
NetworkRunner
when spawning aNetworkRigidbody
prefab at runtime. - Be sure all simulation/controller code executes inside FixedUpdateNetwork().
NetworkRigidbody
The component that synchronizes Rigidbody/Rigidbody2D state from the State Authority to other peers. Should be added on the same game object as the physics rigidbody. Cannot
coexist with other NetworkTRSP
component like NetworkTransform
. Except for teleport operation, any other operations like adding forces or setting the velocity should be
done directly to the Rigidbody/Rigidbody2D on the state authority. The NetworkObject
the component is attached to should ALWAYS be in simulation on Fusion to be in predicted
time, this will be enforced on Spawned().
The following physics properties are networked:
- Linear Velocity
- Angular Velocity
- Mass
- Linear Drag
- Kinematic
- Constraints
If other values are needed they need to be manually synchronized using a custom NetworkBehaviour
.
Area of Interest
NetworkRigidbody
derive from the class NetworkTRSP
, and inherit all of its AOI handling. For Area Of Interest specifics see the NetworkTRSP section of this manual.
Sync Scale
When enabled, transform.localScale
will be synchronized.
Sync Parent
When enabled, transform.parent
will be synchronized. Rigidbodies which have parent Rigidbodies should be set to kinematic. Parented Rigidbodies will automatically set their Object AreaOfInterest Override to the parent Network Object.
There are a few parenting caveats:
- Parent transforms MUST have a
NetworkBehaviour
component. This is how the parent is found, using aNetworkBehaviourId
. - The
NetworkRigidbody
must be on the root of the Network Object (this typically will be the case anyway). - The parent transform can be a child transform of a Network Object. For example the hand of a player.
Interpolation Target
The transform which will be moved for interpolation during Render()
. This typically is a child transform of the Rigidbody which contains no Colliders.
When null, the root of the Network Rigidbody will be moved for interpolation, and will be returned to its tick correct position at the start of the Simulation loop. The InterpolationTarget
value may be changed at runtime via code.
The benefit of using an Interpolation Target rather than the root, is that interpolation will not break physics caching for the object. However, this does make Sync Scale invalid for any child Rigidbodies.
We recommend leaving Interpolation Target null, and only explore using one if you experience some undesired Rigidbody behaviour (in regards to friction/stacking).
Cases where Interpolation Target is necessary:
- Using
MovePosition()
to move a kinematic Rigidbody. Without using an Interpolation Target interpolation is done by setting the transform.position and rotation. Direct changes to the transform like this however override anyMovePosition()
calls to the RB, even if they are made after the transform was modified. - Physics need to be unaffected by interpolation. Interpolating by moving the Transform directly has some side effects, such as breaking the Rigidbodies static friction and sleep.
If an Interpolation Target is used, be sure that it it does not contain any colliders, as moving these will dirty the Rigidbody (which is what we are trying to avoid by using an Interpolation Target). All cosmetic effects should be part of this Interpolation Target.
NOTE: If using both Scale and Parenting, using an Interpolation Target will NOT give correct results. GameObject scale is affected by its parents scale in ways that nearly impossible to replicate via code, so for accurate scale results leaving InterpolationTarget
null is recommended.
NOTE: A common mistake is not having Camera's follow the Interpolation Target. It is important to have cameras follow the Interpolation Target for the Camera to also be interpolated.
Teleport()
See NetworkTransform.Teleport.
RunnerSimulatePhysics
This component is added to the NetworkRunner
prefab, and allows Fusion to handle Physics Simulation.
When the first NetworkRunner
is initialized with this component on the hierarchy, the unity project physics auto simulate will be overwritten to allow for Fusion to handle
the physics simulation, when the last NetworkRunner
is shutdown the original value for both 3D and 2D auto simulate should be restored.
An instance of RunnerSimulatePhysics
is automatically added (if not already exists) on the NetworkRunner when a NetworkRigidbody
is spawned.
Time Scale
Multiplier for value passed to Physics Simulate()
. Use values greater than 1 to accelerate the passing of time and between 0 and 1 to slow time.
Callbacks
OnBeforeSimulate / OnAfterSimulate
Once registered, these methods will be called every time RunnerSimulatePhysics
simulates.
C#
using Fusion;
using Fusion.Addons.Physics;
using UnityEngine;
public class FusionPhysicsAddonExample : NetworkBehaviour
{
private RunnerSimulatePhysics _physicsSimulator;
public override void Spawned()
{
// Get our RunnerSimulatorPhysics instance (this needs to be added to the Runner)
_physicsSimulator = Runner.GetComponent<RunnerSimulatePhysics>();
// Register callback for EVERY simulation tick, be careful as these can be called quite frequently.
_physicsSimulator.OnBeforeSimulate += OnBeforeEverySimulate;
_physicsSimulator.OnAfterSimulate += OnAfterEverySimulate;
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
// Unregister (a good practice)
_physicsSimulator.OnBeforeSimulate -= OnBeforeEverySimulate;
_physicsSimulator.OnAfterSimulate -= OnAfterEverySimulate;
}
private void OnAfterEverySimulate(NetworkRunner runner) {
// Implement code to execute after every Physics.Simulate
}
private void OnBeforeEverySimulate(NetworkRunner runner) {
// Implement code to execute before every Physics.Simulate
}
}
Migrating from Fusion 2.0.X to Fusion 2.1.X
- Replace
NetworkRigidbody3D
orNetworkRigidbody2D
with the unifiedNetworkRigidbody
component. - Replace
RunnerSimulatePhysics3D
orRunnerSimulatePhysics2D
with the unifiedRunnerSimulatePhysics
.
Known issues
- Child Rigidbodies interact with physics in an unpredictable way (even when set to Kinematic), and may collide with objects as if the rigidbody is in a prior position during simulation. Therefore it is recommended that carried objects not rely on collisions, and colliders should be disabled while nested.
- Scale with nesting (parenting) relies on all parents not having Interpolation Targets. If you want to combine scaling with nesting as well as use Interpolation Targets, you will want to write custom handling that allows the interpolation targets to separate from the root and re-parent to the interpolation targets of their parents. Essentially creating a copy of the Rigidbody collider/transform hierarchy with all of the involved interpolation targets.
MovePosition()
andMoveRotation
require the use of an Interpolation Target. Moving kinematic rigidbodies instead by setting transform.position and transform.rotation values directly avoids this requirement.