This document is about: FUSION 2
SWITCH TO

Physics Addon for Fusion 2.1

Level
ADVANCED

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 the NetworkRunner GameObject. Allows Fusion to handle Physics Simulation.

Usage

To use the NetworkRigidbody component follow these steps:

  1. 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.
  2. Add RunnerSimulatePhysics to your NetworkRunner prefab. This component takes over Unity's Physics.Simulate() calls. An instance will be automatically added to the
    NetworkRunner when spawning a NetworkRigidbody prefab at runtime.
  3. 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 a NetworkBehaviourId.
  • 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 any MovePosition() 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 or NetworkRigidbody2D with the unified NetworkRigidbody component.
  • Replace RunnerSimulatePhysics3D or RunnerSimulatePhysics2D with the unified RunnerSimulatePhysics.

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() and MoveRotation require the use of an Interpolation Target. Moving kinematic rigidbodies instead by setting transform.position and transform.rotation values directly avoids this requirement.
Back to top