This document is about: FUSION 2
SWITCH TO

Player

Overview

Player (Player script, Player prefab) represents a connected peer in the game and has no visuals. Player provides access to common metadata - UserID, Nickname, selected character, and other data that should survive the respawn of the Agent (visual representation spawned in the game world).

Agent (Agent script, AgentBase prefab, and its variants) represents an in-game character that is controlled by the player. It is spawned by GameplayMode and has Health, Weapons, and other components. The character is spawned and despawned as needed.

The following diagram shows the component hierarchy as an execution waterfall:

Agent Components

Input Processing

The following diagram illustrates processing input and execution of actions:

Input Processing

Notes:

  1. Frame: Unity frame number (UnityEngine.Time.frameCount). Frames 101 and 102 are incomplete for better readability.
  2. At the start of each frame, input from the device is collected in ProcessFrameInput() and written to the Render Input data structure (input authority only)
  3. The same input is also accumulated into Accumulated Input (for example, look rotation delta)
  4. If the accumulated delta time is big enough to simulate the next fixed tick (frame 103):
    • Accumulated Input is polled/consumed through NetworkEvents.OnInput() callback
    • Player input is read from Fusion in BeforeTick() and stored in Fixed Input (executed on input and state authority)
    • AgentInput.FixedUpdateNetwork() call is forwarded to Agent.EarlyFixedUpdateNetwork() which uses Fixed Input to process movement. This ensures all agents move before anyone starts shooting in current simulation tick
    • Agent.FixedUpdateNetwork() reads Fixed Input and processes shooting
    • AgentInput.Render() call is forwarded to Agent.EarlyRender() which uses Render Input (can also use Accumulated Input) to process render predicted movement and look rotation.
    • Agent.Render() does NOT processes input for render predicted shooting as it is out of the scope of this sample. Shooting is done only in fixed simulation.
  5. If the accumulated delta time is NOT big enough to simulate the next fixed tick (frames 101, 102)
    • AgentInput.Render() call is forwarded to Agent.EarlyRender() (not shown in the graph above for better readability) which uses Render Input (can also use Accumulated Input) to process render predicted movement and look rotation.

This diagram is a simplified version and doesn’t cover all edge cases. For more details check the documented code.

Look Rotation Smoothing

The BR200 comes with a custom solution for a smooth look rotation under any conditions.

The following log illustrates the aliasing problem with raw input when using common hardware (mouse polled with 125Hz rate) and high render/output refresh rate (200+ FPS). The rendered output will always feel jittery, no matter how good the CPU/GPU is.

Look Rotation Smoothing

To fix this problem, input values are recorded with a timestamp, then the value for the current frame is calculated as the average of a defined time span (BR200 uses a 25ms window by default). This results in a butter-smooth perception experience (especially noticeable with a high refresh rate monitor) but introduces a very small input lag. Using hardware with a higher sampling rate allows you to decrease the smoothing window to a minimum.

The following graph shows raw mouse delta (bottom line) and character look rotation (upper line) in time:

Look Rotation Smoothing

The following graph shows smoothed mouse delta (bottom line) and character look rotation (upper line) in time:

Look Rotation Smoothing

This also helps to reduce sampling errors (desk surface) and micro-jitter caused by uneven hand/mouse movement (desk friction, muscles).

Character Animations

The project has a custom animation controller implementation based on the Playables API. It provides support for tick-accurate animation evaluation and dynamic performance scaling.

The following diagram shows the architecture which is similar to the Mecanim:

Animation Controller

Animation layers and states setup in the agent's object hierarchy:

Animation Layers

Animation Layers:

  • Locomotion: Base full body layer for movement
  • FullBody: Override layer for full body actions, blended with Locomotion
  • LowerBody: Override layer for lower body character turning
  • UpperBody: Override layer for upper body actions, usually blended with Locomotion
  • Shoot: Override layer for hands actions (shooting), usually blended with Locomotion
  • Look: Additive upper body layer for looking up and down

Depending on the animation controller complexity, evaluating 200 players can easily become a bottleneck on the server. For better performance, the server allows for interlaced PlayableGraph evaluation every n-th frame based on the connected players count. All important properties like layer or state weight are still calculated every frame. The following table shows the rules for an interlaced evaluation.

Players Connected PlayableGraph Evaluation
> 150 Every 6th frame
> 100 Every 4rd frame
> 50 Every 2nd frame
Otherwise Every frame
This project uses animations baked with the generic rig. Using a humanoid rig would add additional performance overhead due to retargeting

Character Controller

This sample uses Fusion KCC (an advanced kinematic character controller addon) for movement. It is a generic low-level character controller with a strong focus on performance, gameplay interactions, and customization.

Fusion KCC features:

  • Control over position and look rotation (pitch + yaw)
  • Shape defined by Capsule collider
  • Predicted Render movement for local player
  • Combined dynamic (physics-like) and kinematic (unrealistic) velocity based movement
  • External forces - from explosions, moving platforms, …
  • Move acceleration and friction
  • Advanced KCC Processors pipeline for customization (speed and direction override, blocking)
  • Out of the box network synchronization for default properties (radius, height, mass, ...), optional synchronization of other - properties
  • Custom Collider filtering and ignore list
  • CCD (Continuous Collision Detection)
  • Collision callbacks
  • Support for ground snapping and step height
  • Support for local mode (no network traffic)
  • Network & performance optimized
  • Platform independent, mobile friendly
  • Basic support for frame by frame debug - editor drawings and logging

When a player's health is below a certain threshold, and the player is currently out of combat, auto heal kicks in and starts replenishing the player's health.

Jetpack

The jetpack provides the ability to fly and quickly navigate in the level while draining fuel. Fuel can be replenished by picking up fuel cans found in item boxes.

The state of the jetpack is handled by the Jetpack script which handles fuel consumption, propellers, sounds, and on/off state. The actual movement in the air is handled by JetpackKCCProcessor. This script overrides KCC velocities and suppresses default behavior.

Jetpack

Spectator Mode

When players are eliminated or join the game too late, they enter the spectator mode. In spectator mode, players can observe the game from other player's perspectives. In code, this is actually handled quite simply. The camera and UI act based on the ObservedAgent assigned in the SceneContext. The ObservedAgent can be either the local player agent or spectated player agent.

Back to top