This page is a work in progress and could be pending updates.

Fusion 104 - Physics

Overview

Fusion 104 will examine how Fusion interacts with PhysX in a server authoritative game.

At the end of this section, the project will allow the player to spawn and interact with a physics controlled ball.

Consult the Manual for an in-depth description of the settings for this topic

Back To Top

Setup

In hosted mode, Fusion will run the physics simulation on the host and the clients will follow, however the application may optionally allow the clients to predict even physics controlled objects.

To turn on this feature, go to the Fusion menu and select Network Project Config. This opens the Fusion configuration file in the inspector. Under Server Physics Mode choose Client Prediction.

Enabling client prediction is computationally more expensive but provides more accurate movement.

Back To Top

Physics Object

The prefab for a networked, PhysX controlled, object uses the same Rigidbody as a regular Unity PhysX object, but has a different Fusion component to synchronize the visual child object called NetworkRigidbody. This replaces the NetworkTransform as far as networking go.

  1. Create a new empty GameObject in the Unity Editor
  2. Rename GameObject to PhysxBall
  3. Add a new NetworkRigidbody component.
  4. Fusion will show a warning about a missing NetworkObject component, so go ahead and press Add Network Object. Fusion will automatically add a regular Unity RigidBody as well since this is needed for the PhysX simulation.
  5. Change Interpolation Data Source to Predicted and set it to World Space.
  6. Add a Sphere child to PhysxBall
  7. Scale the child down to 0.2 in all directions
  8. Drag the child object into the InterpolationTarget of the NetworkTransform component on the parent object.
  9. Remove the collider from the Sphere
  10. Create a new sphere collider on the parent object with radius 0.1 so that it completely covers the child object.
  11. Add a new script to the game object and call it PhysxBall.cs,
  12. Drag the whole object into the project folder to create a prefab
  13. Save the scene to bake the network object and delete the prefab instance from the scene.

Ball Prefab
Ball Prefab

Back To Top

The PhysxBall Script

Because the ball is driven by PhysX and the NetworkRigidbody takes care of the networked data, it needs less special code to get working than its kinematic cousin. All that needs to be added to PhysxBall.cs is the timer that will despawn the ball after a few seconds (this is exactly the same as for the kinematic ball), as well as a method to set the initial forward velocity.

Both are covered by the Init() method, like this:

using UnityEngine;
using Fusion;

public class PhysxBall : NetworkBehaviour
{
  [Networked] private TickTimer life { get; set; }

  public void Init(Vector3 forward)
  {
    life = TickTimer.CreateFromSeconds(Runner, 5.0f);
    GetComponent<Rigidbody>().velocity = forward;
  }

  public override void FixedUpdateNetwork()
  {
    if(life.Expired(Runner))
      Runner.Despawn(Object);
  }
}

Back To Top

Input

To spawn the ball, the code needs to be extended following the same three steps as for the kinematic ball, but changed to use the second mouse button instead:

1. NetworkInputData

In NetworkInputData.cs Simply add a new button flag:

using Fusion;
using UnityEngine;

public struct NetworkInputData : INetworkInput
{
  public const byte MOUSEBUTTON1 = 0x01;
  public const byte MOUSEBUTTON2 = 0x02;

  public byte buttons;
  public Vector3 direction;
}

Back To Top

2. BasicSpawner

In BasicSpawner.cs Poll the second mouse button in the same fashion as the first, and set the flag accordingly:

  private bool _mouseButton0;
  private bool _mouseButton1;
  private void Update()
  {
    _mouseButton0 = _mouseButton0 || Input.GetMouseButton(0);
    _mouseButton1 = _mouseButton1 || Input.GetMouseButton(1);
  }

  public void OnInput(NetworkRunner runner, NetworkInput input)
  {
    var data = new NetworkInputData();

    ...

    if (_mouseButton1)
      data.buttons |= NetworkInputData.MOUSEBUTTON2;
    _mouseButton1 = false;

    input.Set(data);
  }

Back To Top

3. Player

Player.cs holds the code that spawns the actual ball prefab so in addition to needing a prefab reference like this,

[SerializeField] private PhysxBall _prefabPhysxBall;

the Player must also call spawn and set the velocity (just a constant multiplied to the last forward direction) using the Init() method created earlier.

public override void FixedUpdateNetwork()
{
  if (GetInput(out NetworkInputData data))
  {
    data.direction.Normalize();
    _cc.Move(5*data.direction*Runner.DeltaTime);

    if (data.direction.sqrMagnitude > 0)
      _forward = data.direction;

    if (delay.ExpiredOrNotRunning(Runner))
    {
      if ((data.buttons & NetworkInputData.MOUSEBUTTON1) != 0)
      {
        delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
        Runner.Spawn(_prefabBall, 
          transform.position+_forward,
          Quaternion.LookRotation(_forward), 
          Object.InputAuthority, 
          (runner, o) =>
          {
            // Initialize the Ball before synchronizing it
            o.GetComponent<Ball>().Init();
          });
      }
      else if ((data.buttons & NetworkInputData.MOUSEBUTTON2) != 0)
      {
        delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
        Runner.Spawn(_prefabPhysxBall, 
          transform.position+_forward, 
          Quaternion.LookRotation(_forward),           
          Object.InputAuthority, 
          (runner, o) =>
          {
            o.GetComponent<PhysxBall>().Init( 10*_forward );
          });
      }
    }
  }
}

Finally, to test the new ball, assign the created prefab to the Prefab Physx Ball field on the Player prefab, build and run.

To Document Top