- Input Processing
- Character Animations
- Character Controller
- Spectator Mode
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).
AgentBase prefab, and its variants) represents an in-game character that is controlled by the player. It is spawned by
GameplayMode and has
Weapons, and other components. The character is spawned and despawned as needed.
The following diagram shows the component hierarchy as an execution waterfall:
The following diagram illustrates processing input and execution of actions:
Frame: Unity render frame number,
Tick: Fusion fixed update tick number
- At the start of each frame, input from the device is collected in
BeforeUpdate()and written to the
Render Inputdata structure (executed on input authority only)
- The same input is also accumulated into
Cached Input(for example, look rotation delta)
- If the accumulated delta time is big enough to simulate the next fixed tick (frame 103)
Cached Inputis polled/consumed through
- Because the most recent
Render Inputis already accumulated and will be processed in the following
FixedUpdateNetwork(), it needs to be cleared, so it is not applied twice (from
- Player input is read from Fusion in
BeforeTick()and stored in
Fixed Input(executed on input and state authority)
FixedUpdateNetwork()called in other scripts use
Fixed Inputto generate gameplay actions
Render()called in other scripts use
Render Inputto generate gameplay actions (render predicted movement, shooting is done only from FUN)
- If the accumulated delta time is NOT big enough to simulate the next fixed tick (frames 101, 102)
Render()called in other scripts use
Cached Inputto generate gameplay actions (render predicted movement, 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
Fusion BR 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.
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 (Fusion BR 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:
The following graph shows smoothed mouse delta (bottom line) and character look rotation (upper line) in time:
This also helps to reduce sampling errors (desk surface) and micro-jitter caused by uneven hand/mouse movement (desk friction, muscles).
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
Animation layers and states setup in the agent's object hierarchy:
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 4th frame|
|> 100||Every 3rd frame|
|> 50||Every 2nd frame|
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.
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.
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
ObservedAgent can be either the local player agent or spectated player agent.