Overview
Overview
The Physics addon includes components necessary for client prediction and synchronization of Rigidbody and Rigidbody2D components.
NetworkRigidbody3D
- Synchronizes Rigidbody state from the State Authority to other peers.NetworkRigidbody2D
- Synchronizes Rigidbody2D state from the State Authority to other peers.RunnerPhysicsSimulate3D
- Optional component which may be added to the NetworkRunner GameObject. Allows Fusion to handle Physics Simulation.RunnerPhysicsSimulate2D
- Optional component which may be added NetworkRunner GameObject, Allows Fusion to handle Physics2D Simulation.
Usage
To use the Network Rigidbody components follow these steps:
- Add
NetworkRigidbody3D
(orNetworkRigidbody2D
for 2D) andNetworkObject
to a rigidbody 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
RunnerSimulatePhysics3D
(or 2D if applicable) to yourNetworkRunner
prefab. This component takes over Unity's Physics.Simulate() calls. - Be sure all simulation/controller code executes inside of FixedUpdateNetwork().
Migrating from Fusion 1 to Fusion 2
IBeforePhysicsStep
andIAfterPhysicsStep
callbacks have been removed, and can be replaced with callbacks inRunnerSimulatePhysics
. See Callbacks below.
Extending / Modifying
The NetworkRigidbody
and RunnerSimulatePhysics
components are designed to work for most use cases. However, you may want to modify these to meet your own project specific needs. Some members of these classes are virtual and can be overridden. However, in most cases you will probably want to make your own class using these components as guides, or may just modify them directly. No internals of the Fusion core rely on these components (though some Samples and Demos may), so you may modify them as you see fit.
NetworkRigidbody2D / NetworkRigidbody3D
NetworkRigidbody3D
and NetworkRigidbody2D
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. The Render Sleep Thresholds mitigate this, but there may be some cases were any interference is unacceptable.
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.
Sleep Thresholds
When enabled, interpolation of the root transform will not happen if the changes to the current transform state would fall below all of the indicated threshold values. This mitigates the effects of moving the root transform - which breaks physics caching, and prevents sleep. Allowing sleep is especially important for the Server Authority instance, as it will generate network traffic even when moving very slightly. Allowing rigidbodies to sleep greatly reduces network traffic.
Note: Only Sleep Thresholds are only applicable when an Interpolation Target is not being used.
Use Render Sleep Thresholds
Enables the checks for thresholds. When disabled, the object is always interpolated.
Render Thresholds
- Use Energy - Tests if energy level of velocity and angular velocity of the local rigidbody are above the sleep threshold, and will interpolate if so.
- Position: If interpolation would produce a position change to the current transform state greater than this value, then interpolation will occur. A value of 0 excludes Position from the test.
- Rotation: If interpolation would produce a rotation angle change to the current transform state greater than this value, then interpolation will occur. A value of 0 excludes rotation from the test.
- Scale: If interpolation would produce a local scale change to the current transform state greater than this value, then interpolation will occur. A value of 0 excludes scale from the test.
Teleport()
See NetworkTransform.Teleport.
MovingTeleport()
Initiates a moving teleport. This method must be called in FixedUpdateNetwork()
before RunnerSimulatePhysics3D
and RunnerSimulatePhysics2D
have simulated physics. This teleport is deferred until after physics has simulated, and captures position and rotation values both before and after simulation. This allows interpolation leading up to the teleport to have a valid pre-teleport TO target. This is an alternative to the basic Teleport(), which causes interpolation to freeze for one tick.
RunnerPhysicsSimulate2D / RunnerPhysicsSimulate3D
These components may be added to the NetworkRunner
prefab, and allows you to specify how you want physics simulation to be handled. If Every FixedUpdateNetwork()
this component will call the applicable Physics Simulate()
.
Physics Authority
Indicates whether Fusion will use this component to call Physics.Simulate()
/Physics2D.Simulate()
or if that will be left to Unity's Physics settings (auto-simulate or script modes).
Auto
indicates that Fusion will take over Simulate()
calls if:
- Game is running in any Game Mode other than Shared Mode. Shared Mode by default assumes users are moving objects outside of
FixedUpdateNetwork()
. If your controller code applies inside ofFixedUpdateNetwork()
, then it is necessary to add this component and set thePhysicsAuthority
to Fusion. - Multi-Peer mode is enabled. Unity does not auto-simulate non-primary Physics scenes, so any time Multi-Peer mode is used Fusion needs to control the
Simulate()
calls.
Physics Timing
Indicates which timing segment is to be used if Fusion is the Physics Authority
.
Client Physics Simulation
Controls physics simulation on clients. The options are:
- Disabled: Physics simulation doesn't run on clients and transforms are not synced to PhysX engine.
- SyncTransforms: UnityEngine.Physics.SyncTransform() is called in all ticks.
- SimulateForward: UnityEngine.Physics.SyncTransform() is called in resimulation ticks, UnityEngine.Physics.Simulate() is called in forward ticks.
- SimulateAlways: UnityEngine.Physics.Simulate() is called in all tick.
⚠️ Server always simulates physics. In Shared mode, SimulateForward
and SimulateAlways
behaves the same as there are only forward ticks simulated.
DeltaTime Multiplier
Multiplier for value passed to Physic's Simulate()
. Use values greater than 1 to accelerate the passing of time and between 0 and 1 to slow time.
Set FixedTimestep
When enabled, this component will set Unity's Time FixedTimestep
value to match Fusion's DeltaTime. The helps ensure any user code inside of FixedUpdate at mostly in agreement with Fusion's ticks.
IMPORTANT: FixedUpdate()
and FixedUpdateNetwork()
will never be fully aligned. All attempts should be made to avoid mixing usages of these two timing segments. Typically with Fusion all simulation code should be in FixedUpdateNetwork()
, with the exception of Shared Mode where changes in Update()
may be desired or necessary.
Callbacks
INetworkRunnerCallbacks.IBeforePhysicsStep
and INetworkRunnerCallbacks.IAfterPhysicsStep
have been removed in Fusion 2, and have been replaced with the following.
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 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
These callbacks queue a one time callback that will trigger the next time a Simulation occurs.
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
}
}
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.
- Overview
- Usage
- Migrating from Fusion 1 to Fusion 2
- Extending / Modifying
- NetworkRigidbody2D / NetworkRigidbody3D
- Sync Scale
- Sync Parent
- Interpolation Target
- Sleep Thresholds
- Use Render Sleep Thresholds
- Render Thresholds
- Teleport()
- MovingTeleport()
- RunnerPhysicsSimulate2D / RunnerPhysicsSimulate3D
- Physics Authority
- Physics Timing
- Client Physics Simulation
- DeltaTime Multiplier
- Set FixedTimestep
- Callbacks
- Known issues