Advanced Forecast Vehicle Physics
This sample uses the Fusion SDK 2.1.0 which is in development and early access is available to Circle members only.
Overview
The Advanced Forecast Vehicle Physics
sample is an expansion of the result of the Essential Forecast Vehicle Physics
tutorial which can be found here.
This sample expands on the tutorial in a number of ways:
- Interactable physics objects
- Automatic switching of state authority
- Reset functionality for cars
There is no set goal or target for the player to achieve in this sample. Feel free to explore and experiment with driving over and around the different obstacles and interact with the physical objects.

Download
Version | Release Date | Download |
---|---|---|
2.1.0 | 8月 12, 2025 | Advanced Forecast Vehicle Physics 2.1.0 |
Starting the Sample
The sample immediately starts a Shared Mode game where your car is spawned into the world. There is a brief explanation of controls and then the camera will zoom down to start following your vehicle after clicking anywhere on screen.
Other players will be able to join the game and appear is separate cars in the same world.
The Player ID for the player with authority over a car or object is displayed on its sides. This is useful to determining who is who when playing.
Physics Forecast
Physics Forecast
in enabled in the Network Project Config Asset
for this sample. Having this feature enabled allows for Forecast Physics extrapolation. When disabled the Physics is synchronised to remote time. Having this feature enabled allows for more accurate local time synchronisation of objects and their velocities between clients.
Interactable Physics Objects
Overview
There are two types of physics object placed in the world:
- Cubes: These are relatively heavy and cars can just about move and knock them over.
- Ball: This is a large relatively light weight ball that can be easily pushed around by the cars.
Both of these objects were created using the following process:
- Right click in the scene hierarchy view
3D OBject > Sphere/Cube
. This creates aGameObject
in the scene with aMesh
and aCollider
. - Add a
RigidBody
component and adjust the settings to your liking. - Add
NetworkTransform
andNetworkObject
Fusion components.
After the three steps above the new object should be networked and players can interact with it and its position will be synchronised. However, the player that has authority over the object is the first player that joined, and by default when this player leaves the object will be destroyed. This default behaviour is useful in some cases, but not for this sample.
To solve this issue we could tick the Is Master Client Object
box on the NetworkObject
component. This would make the object authority automatically switch to the Shared Mode Master Client
whenever it changes. If the first player was to leave the object would not be destroyed and instead would have its authority switch to the new Shared Mode Master Client
.
However, we did not rely on Is Master Client Object
functionality for the Ball and Cubes in this sample, the following section describes how authority was switched in this use case.
Automatic Authority Switching
The Cubes and Ball in this tech sample physically interact with the cars as they knock into them. As the ball is so light weight it is particularly responsive to subtle changes to car position, steering, and velocity as the ball is hit and pushed along. Given slight network delays and discrepancies in physics simulations there can be slight differences in behaviour between the authority and other players. This sample has opted to make this interaction as responsive and predictable as possible for the player actually interacting with the ball. To do this we have added logic to adjust who has authority over the object based on the distance to it. The end result most of the time is that the player who is hitting the object has authority both over their car and the object. They are the authority for the entire physics interaction. This gives the best player experience as they are not susceptible to corrections from any other authority.
The relatively simple approach can be found in the DistanceBasedAuthority.cs
script. This is a NetworkBehaviour
component so that is has access to the Object
and Runner
.
For this script to be able to function the following options need to be set on the Object NetworkObject
component:
Is Master Client Object
needs to beFalse
Allow State Authority Override
needs to beTrue
Destroy When State Authority Leaves
needs to beFalse
The logic relies on the fact that the Car for the local and authority player can be retrieved with the following:
C#
// Find the player object of the player that currently has authority
var authorityPlayerObject = Runner.GetPlayerObject(Object.StateAuthority);
...
// Find the player object of the local player
var localPlayerObject = Runner.GetPlayerObject(Runner.LocalPlayer);
Note: This relies on the fact that the Player Object for the player was set to the car in the spawner script, see CarSpawner.cs
for more details.
Once the references to the cars are found it's a case of comparing their distances to the object and swapping the authority to the local player if it is nearer:
C#
// Compare local player object distance to this object with the distance to the auth player object from this object
// Optimisation: As we are only comparing the distances we can avoid using the square route used when calling Vector3.Distance()
// and instead just use sqrMagnitude.
float playerObjectWithAuthorityDistanceSquared = (transform.position - authorityPlayerObject.transform.position).sqrMagnitude;
float localPlayerObjectDistanceSquared = (transform.position - localPlayerObject.transform.position).sqrMagnitude;
// Request authority over the this object if the local player object is the closest
if (localPlayerObjectDistanceSquared < playerObjectWithAuthorityDistanceSquared) {
Object.RequestStateAuthority();
}
Note: Please see the script for more details of how it handles initialisation, edge cases and prevents constant authority changes if two cars are equally far away from the object.
Displaying the Player ID on the objects and cars
PlayerIDTextSetter.cs
is the script that is responsible for displaying the Player ID with the state authority on the side of objects. In the case of Balls and Cubes it will additionally display either P
or M
depending on if the player is a normal player or the Shared Mode Master Client
. In the case of the Car it will also display this information in the form of PLYR
or MSTR
on the number plate.
The script works by making use of two Networked properties: the _stateAuthorityPlayerID
and the _stateAuthorityPlayerIsSharedModeMasterClient
. These properties are set by the player that has authority in FixedNetworkUpdate()
and is synchronised with all other clients, allowing all clients to display the same correct information.
Each property uses the OnChangedRender
attribute, It allows a method to be called when the property is changed. In this case we are calling OnPlayerIDChanged
. This method simply updates all of the TextMeshPro
elements that have been associated with this component in the inspector.
C#
// The player ID and the master client status is networked so that all clients can display the same values.
// Only the player with the state authority over the network object can set these values.
[Networked, OnChangedRender(nameof(OnPlayerIDChanged))]
int _stateAuthorityPlayerID { get; set; }
[Networked, OnChangedRender(nameof(OnPlayerIDChanged))]
NetworkBool _stateAuthorityPlayerIsSharedModeMasterClient { get; set; }
Reset Functionality
The R
button can be pressed to reset the car back to the starting area. This is achieved by using the NetworkTransform.Teleport()
method. It is important to use this method when you require the object to be instantly 'teleported' on every client. If the transform or RigidBody position is adjusted instead then it may look like the object has teleported on the authorities screen, but on other clients the object position will be "corrected" and therefore move to the new position over a number of frames.
C#
// Reset method to teleport the car back to its starting position
void Reset() {
if (TryGetComponent(out NetworkTransform nt)) {
nt.Teleport(_initialSpawnPosition, _initialSpawnRotation);
// Remove all velocity when resetting
_rigidBody.velocity = Vector3.zero;
_rigidBody.angularVelocity = Vector3.zero;
}
}
Back to top