Sync Idle, Run & Attack Animations
This page accompanies the Photon Fusion 2 Tutorial – Sync Idle, Run & Attack Animations video and explains how to synchronize character animations in Photon Fusion Shared Mode.
Use this page when implementing networked animation states such as idle, walking, running, attacking, interacting, or performing temporary actions.
If you would like to dive deeper into Animations or the Network Mecanim Animator, you can visit the dedicated pages via both links.
Overview
Fusion provides multiple approaches for synchronizing Unity Animator state.
The simplest option is the built-in NetworkMecanimAnimator. It can synchronize Animator parameters with minimal custom networking code.
A more explicit option is to synchronize only the required gameplay values through [Networked] properties and update the Unity Animator from Render().
This video demonstrates both approaches:
- synchronizing idle and walking with
NetworkMecanimAnimator; - synchronizing an attack trigger;
- buffering rendered-frame input for Fusion ticks;
- replacing
NetworkMecanimAnimatorwith custom Networked properties; - updating visual animation state from
Render(); - comparing convenience, bandwidth, and control;
- preventing repeated or spammed trigger updates;
- identifying when tick-accurate animation systems are required.
Video Timeline
| Time | Section |
|---|---|
| 00:00 | Introduction |
| 00:19 | Project setup and verification |
| 00:57 | Idle and walking animations |
| 02:59 | NetworkMecanimAnimator overview |
| 04:26 | Scripting for NetworkMecanimAnimator |
| 07:20 | Attack animation and trigger synchronization |
| 09:40 | Two animation synchronization methods |
| 10:54 | Synchronizing animations with Networked properties |
| 14:03 | Testing |
| 14:07 | Fixing a potential spam issue |
| 14:35 | Tick-based animations technical sample |
| 15:09 | Outro |
Project Setup
Before configuring animation synchronization, verify the Fusion project setup.
Open:
Tools > Fusion > Fusion Hub
Confirm that the project has a valid Fusion App ID.
When the sample starts:
- Click
Start Client. - Wait for the player prefab to spawn.
- Verify that movement and connection already work.
- Confirm that the character currently moves without playing animation.
The sample already includes:
- Shared Mode connection logic;
- player spawning;
- a
NetworkObject; - a networked character controller;
- player movement.
The tutorial focuses only on animation setup and synchronization.
Character Prefab
Open the player prefab in the project’s animation folder.
The character already contains the core networking and movement components.
The relevant setup includes:
| Component | Purpose |
|---|---|
NetworkObject |
Gives the player a Fusion network identity. |
| Network character controller | Handles synchronized player movement. |
Animator |
Plays Unity animation states. |
| Character model | Contains the animated skeleton and renderer. |
The next step is to create the Unity Animator Controller.
Preparing Animation Clips
The sample uses character and animation assets from Kenney.
The required clips are:
- idle;
- walk;
- attack.
If the clips are embedded inside an FBX file, duplicate or extract them into separate project assets.
For each clip:
- Select the clip inside the FBX asset.
- Duplicate or extract it into the project.
- Rename it clearly.
- Configure looping where required.
Enable Loop Time for:
- idle;
- walk.
Do not normally enable looping for a one-shot attack animation.
Creating the Animator Controller
Drag the idle animation onto the character to create an Animator Controller automatically.
Open:
Window > Animation > Animator
Create a Blend Tree for locomotion.
The Blend Tree contains:
- idle;
- walk.
Create a float parameter named:
Speed
The Blend Tree uses Speed to blend between idle and walking.
A simple setup can use:
| Speed | Animation |
|---|---|
0 |
Idle |
| Positive movement value | Walk or run |
The exact threshold depends on the character controller’s velocity range.
Animator Parameters
The tutorial uses two Animator parameters:
| Parameter | Type | Purpose |
|---|---|---|
Speed |
Float | Blends between idle and movement. |
Attack |
Trigger | Starts the one-shot attack animation. |
Parameter names in code must match the Animator Controller exactly.
To avoid repeated string lookups, cache parameter hashes.
Example:
C#
private static readonly int SpeedHash =
Animator.StringToHash("Speed");
private static readonly int AttackHash =
Animator.StringToHash("Attack");
Approach 1: NetworkMecanimAnimator
Fusion includes:
NetworkMecanimAnimator
This component integrates Unity’s Animator with Fusion network synchronization.
Add it to the player prefab and assign the character’s Animator.
The component can synchronize supported Animator parameters across the network.
This is useful when:
- prototyping;
- synchronizing a small Animator Controller quickly;
- minimizing custom networking code;
- implementing non-critical animation state.
NetworkMecanimAnimator Setup
On the player prefab:
- Add
NetworkMecanimAnimator. - Assign the Unity
Animator. - Review the component’s synchronization settings.
- Configure the parameters that need to be synchronized.
- Save or apply the prefab changes.
Supported Animator parameter categories can include:
- floats;
- integers;
- booleans;
- triggers.
Only synchronize parameters that affect the required networked visual result.
PlayerAnimatorNMA
Create a new script:
PlayerAnimatorNMA
The script inherits from:
C#
NetworkBehaviour
Its responsibilities are:
- cache the movement controller;
- cache the
NetworkMecanimAnimator; - calculate movement speed;
- update the Animator’s speed parameter;
- submit attack triggers;
- buffer attack input between Unity frames and Fusion ticks.
Caching References
The script needs references to:
- the Animator;
- the character movement controller;
- the
NetworkMecanimAnimator.
Example:
C#
using Fusion;
using UnityEngine;
public class PlayerAnimatorNMA : NetworkBehaviour
{
[SerializeField]
private Animator _animator;
[SerializeField]
private NetworkMecanimAnimator _networkAnimator;
[SerializeField]
private NetworkCharacterController _characterController;
private static readonly int SpeedHash =
Animator.StringToHash("Speed");
private static readonly int AttackHash =
Animator.StringToHash("Attack");
}
The exact movement controller type depends on the sample.
Calculating Movement Speed
In FixedUpdateNetwork(), read the character’s velocity.
For locomotion animation, horizontal speed is usually more useful than total 3D speed.
Conceptually:
C#
public override void FixedUpdateNetwork()
{
Vector3 velocity =
_characterController.Velocity;
velocity.y = 0f;
float speed = velocity.magnitude;
_animator.SetFloat(
SpeedHash,
speed
);
}
Removing the vertical component prevents jumping or falling from being interpreted as horizontal running.
Authority and Animation Input
Only the player that controls the object should read local device input and submit animation actions.
In Shared Mode, this commonly means checking:
C#
Object.HasStateAuthority
before reading attack input or modifying authoritative Networked state.
Proxy players should display synchronized animation results, not read the local keyboard.
Attack Animation Setup
Add the attack animation to the Animator Controller.
A common setup is:
- Add an
Attackstate. - Create a transition from
Any StatetoAttack. - Add the
Attacktrigger condition. - Create a transition from
Attackback to locomotion. - Remove or reduce transition duration for a responsive result.
- Disable looping on the attack clip.
The attack should play once and then return to the locomotion Blend Tree.
Capturing Attack Input
Unity input is read during rendered frames.
Fusion simulation updates occur on network ticks.
A one-frame key press can be missed if it is checked only during FixedUpdateNetwork().
Buffer the attack request in Update():
C#
private bool _isAttacking;
private void Update()
{
if (!Object ||
!Object.HasStateAuthority)
{
return;
}
_isAttacking |=
Input.GetKeyDown(KeyCode.Space);
}
Using |= preserves an earlier press until the next network tick consumes it.
Consuming the Attack Request
In FixedUpdateNetwork():
C#
public override void FixedUpdateNetwork()
{
UpdateMovementAnimation();
if (!_isAttacking)
{
return;
}
_isAttacking = false;
_networkAnimator.SetTrigger(
AttackHash
);
}
The request is cleared after it has been sent.
This prevents one key press from repeatedly triggering the animation.
Why Use NetworkMecanimAnimator.SetTrigger?
Do not use only:
C#
_animator.SetTrigger(AttackHash);
for a networked trigger that other peers need to observe.
Use:
C#
_networkAnimator.SetTrigger(AttackHash);
so Fusion synchronizes the trigger through NetworkMecanimAnimator.
A direct Animator trigger affects only the local Unity Animator unless another synchronization mechanism is implemented.
Testing NetworkMecanimAnimator
Test with multiple clients.
- Start the first client.
- Move the character.
- Confirm that idle and walking blend correctly.
- Trigger the attack.
- Start a second client.
- Observe the first character remotely.
- Verify that locomotion and attack animation appear on both peers.
Check the result from:
- the local player;
- the remote proxy;
- both directions between two players.
Advantages of NetworkMecanimAnimator
NetworkMecanimAnimator provides:
- quick setup;
- minimal custom synchronization code;
- direct integration with Animator parameters;
- built-in trigger support;
- a practical prototyping workflow.
It is suitable when development speed matters more than fine-grained control.
Limitations of NetworkMecanimAnimator
Automatic Animator synchronization can replicate more data than the project actually needs.
Potential limitations include:
- synchronization overhead for multiple parameters;
- less control over the exact network representation;
- tighter coupling between Animator Controller parameters and network data;
- reduced ability to optimize values individually;
- limited suitability for deterministic, tick-critical combat animation.
For production projects, manual Networked properties can provide more explicit control.
Approach 2: Networked Properties
The second approach removes NetworkMecanimAnimator.
Instead, the project defines only the Networked values required for animation.
Create:
PlayerAnimatorNetworkProperties
The script uses:
- a Networked speed value;
- a Networked attack counter;
FixedUpdateNetwork()for state updates;Render()for Animator presentation.
Separating State from Presentation
With this approach:
FixedUpdateNetwork()writes synchronized gameplay-facing values;Render()reads those values and updates the Unity Animator.
This follows a clear separation:
| Method | Responsibility |
|---|---|
FixedUpdateNetwork() |
Write or update network state. |
Render() |
Apply network state to visual presentation. |
The Animator remains a Unity presentation component rather than the source of network state.
Networked Speed
Define only the locomotion value required by the Animator:
C#
[Networked]
private float NetSpeed { get; set; }
In FixedUpdateNetwork():
C#
public override void FixedUpdateNetwork()
{
if (Object.HasStateAuthority)
{
Vector3 velocity =
_characterController.Velocity;
velocity.y = 0f;
NetSpeed = velocity.magnitude;
}
}
Only State Authority writes the property.
Fusion replicates the value to proxies.
Updating the Animator from Render
In Render():
C#
public override void Render()
{
_animator.SetFloat(
SpeedHash,
NetSpeed
);
}
Every peer uses the synchronized NetSpeed value to update its local Animator.
This includes:
- the authoritative player;
- remote proxies;
- interpolated render state.
Synchronizing an Attack Event
An attack trigger is an event rather than a continuous state.
A Networked counter can represent how many attack events have occurred.
Example:
C#
[Networked]
private byte AttackCount { get; set; }
When the player attacks:
C#
AttackCount++;
A byte is sufficient when only change detection is required and wraparound is acceptable.
Why Use a Counter Instead of a Boolean?
A boolean can fail to represent repeated identical events.
For example:
Attack = true.- The attack plays.
- Another attack occurs while the value is still
true. - No Networked value change occurs.
A counter changes for every event:
0 → 1 → 2 → 3
Even if the same animation plays repeatedly, each increment represents a new attack.
Detecting Attack Changes
Store the last rendered attack count locally:
C#
private byte _lastAttackCount;
In Render():
C#
public override void Render()
{
_animator.SetFloat(
SpeedHash,
NetSpeed
);
if (_lastAttackCount != AttackCount)
{
_lastAttackCount = AttackCount;
_animator.SetTrigger(
AttackHash
);
}
}
The trigger fires only when the synchronized counter changes.
Initializing the Local Counter
When the object spawns, initialize the local comparison value.
Example:
C#
public override void Spawned()
{
_lastAttackCount = AttackCount;
}
This prevents a proxy from interpreting the initial Networked value as a new attack event.
The required initialization can vary depending on when Render() first executes and how spawned objects are initialized.
Full Manual Synchronization Example
A simplified implementation can look like:
C#
using Fusion;
using UnityEngine;
public class PlayerAnimatorNetworkProperties :
NetworkBehaviour
{
[SerializeField]
private Animator _animator;
[SerializeField]
private NetworkCharacterController
_characterController;
[Networked]
private float NetSpeed { get; set; }
[Networked]
private byte AttackCount { get; set; }
private bool _attackRequested;
private byte _lastAttackCount;
private static readonly int SpeedHash =
Animator.StringToHash("Speed");
private static readonly int AttackHash =
Animator.StringToHash("Attack");
private void Update()
{
if (!Object ||
!Object.HasStateAuthority)
{
return;
}
_attackRequested |=
Input.GetKeyDown(KeyCode.Space);
}
public override void Spawned()
{
_lastAttackCount = AttackCount;
}
public override void FixedUpdateNetwork()
{
if (!Object.HasStateAuthority)
{
return;
}
Vector3 velocity =
_characterController.Velocity;
velocity.y = 0f;
NetSpeed = velocity.magnitude;
if (_attackRequested)
{
_attackRequested = false;
AttackCount++;
}
}
public override void Render()
{
_animator.SetFloat(
SpeedHash,
NetSpeed
);
if (_lastAttackCount ==
AttackCount)
{
return;
}
_lastAttackCount =
AttackCount;
_animator.SetTrigger(
AttackHash
);
}
}
The exact controller APIs and authority checks depend on the sample architecture.
Preventing Attack Spam
A potential issue occurs when the attack request remains active across multiple ticks.
If it is not cleared correctly, the attack counter can increment every network tick.
Ensure the buffered request is reset immediately after consumption:
C#
if (_attackRequested)
{
_attackRequested = false;
AttackCount++;
}
Additional gameplay restrictions can include:
- attack cooldown;
- animation-state validation;
- weapon cooldown;
- stamina requirements;
- action locks;
- server or authority validation.
Attack Cooldown
For production gameplay, do not rely only on animation duration to prevent repeated attacks.
Store gameplay cooldown state using Fusion-compatible state such as:
C#
TickTimer
Conceptually:
C#
[Networked]
private TickTimer AttackCooldown {
get;
set;
}
Then allow a new attack only when the timer has expired.
Animation state should represent gameplay state rather than define whether gameplay actions are legal.
Comparing Both Approaches
| Criteria | NetworkMecanimAnimator | Manual Networked Properties |
|---|---|---|
| Setup speed | Faster | More implementation work |
| Custom code | Minimal | Explicit |
| Parameter control | Component-driven | Fully controlled by project code |
| Network data | Can synchronize several Animator parameters | Only declared values are synchronized |
| Trigger support | Built in | Implemented with counters or state |
| Optimization | Convenient but less granular | More granular |
| Prototyping | Strong fit | More work than necessary |
| Production control | Suitable for many projects | Better when explicit bandwidth control matters |
| Tick-critical combat | Limited by normal Mecanim presentation | Requires a more advanced tick-based approach |
When to Use NetworkMecanimAnimator
Use NetworkMecanimAnimator when:
- prototyping;
- building a small co-op game;
- animation synchronization is mostly visual;
- the Animator Controller is simple;
- minimal implementation time is preferred;
- tick-accurate animation is not required.
When to Use Networked Properties
Use custom Networked properties when:
- only a few values need synchronization;
- bandwidth should be controlled explicitly;
- networking should remain independent from Animator configuration;
- animation state needs custom validation;
- events need a compact representation;
- presentation logic should be driven from
Render().
Animation State vs Gameplay State
Animation should generally visualize gameplay state.
For example:
- velocity determines the locomotion animation;
- an accepted attack action increments the attack counter;
- a gameplay death state selects the death animation;
- a weapon state determines reload animation.
Avoid making the Animator the authority for critical gameplay logic.
The Animator can be affected by:
- blending;
- transition timing;
- local frame rate;
- presentation settings;
- animation speed.
Critical gameplay state should remain in Networked simulation data.
Tick-Accurate Animations
Normal Mecanim synchronization is suitable for many visual animation requirements.
Competitive games may require animation to be aligned precisely with simulation ticks.
Examples include:
- fighting-game hitboxes;
- melee collision windows;
- competitive shooter reload states;
- frame-specific invulnerability;
- deterministic combat timing;
- rollback-sensitive attacks.
For these cases, use the Fusion Animations technical sample and its tick-accurate animation patterns.
Tick-Accurate Combat
In a tick-critical system, gameplay should know the exact simulation tick for:
- attack start;
- active hitbox window;
- recovery period;
- animation completion;
- cancel window;
- damage application.
The Unity Animator can display the result, but gameplay timing should be represented in network state.
Render Method
Render() is called for Unity presentation updates.
It is a suitable place to apply synchronized values to:
- Animator parameters;
- model transforms;
- visual effects;
- UI;
- cosmetic state.
Do not use Render() to modify authoritative Networked properties.
FixedUpdateNetwork Method
FixedUpdateNetwork() is Fusion’s tick-based simulation callback.
Use it for:
- reading network input;
- updating Networked properties;
- validating attack requests;
- calculating synchronized movement state;
- changing gameplay state.
Keep visual Animator updates separate where possible.
Float Synchronization Considerations
A raw float speed value may change frequently.
Projects can reduce network variation by:
- normalizing the speed range;
- quantizing the value;
- synchronizing a smaller state enum;
- synchronizing movement intent instead of exact velocity;
- applying thresholds before updating;
- deriving animation speed locally from synchronized movement.
The best approach depends on animation quality and bandwidth requirements.
State-Based Locomotion Alternative
Instead of synchronizing a float, a project can synchronize a compact locomotion state:
C#
public enum LocomotionState : byte
{
Idle,
Walk,
Run
}
This reduces data but removes continuous blending unless the client derives a blend value locally.
Use a float when smooth blending is important.
Use an enum when discrete animation states are sufficient.
Testing
Test with at least two clients.
Verify:
- Local idle animation.
- Remote idle animation.
- Local walk or run animation.
- Remote walk or run animation.
- Local attack playback.
- Remote attack playback.
- Repeated attacks.
- Joining while another player is already moving.
- Joining during or after an attack.
- Different network conditions.
Late Join Behavior
Current Networked properties are available to late joiners.
A late joiner can receive:
- current speed;
- current movement state;
- current persistent animation state.
A one-shot attack that already finished should not normally replay for a late joiner.
The counter pattern represents event history numerically, so initialize local comparison state carefully to avoid replaying old events on spawn.
Animator Transition Configuration
Networking code can be correct while the Animator still produces poor results.
Check:
- transition duration;
- exit time;
- interruption settings;
- looping;
- Blend Tree thresholds;
- attack return transition;
- layer weights;
- avatar configuration.
For a responsive attack:
- use a short transition into attack;
- avoid unexpected exit-time delays;
- ensure the state returns to locomotion;
- prevent unintended looping.
Root Motion
The tutorial synchronizes animations for a character whose movement is controlled by the network character controller.
If Root Motion is enabled, animation can also move the character.
This creates additional networking considerations.
For standard networked movement:
- keep gameplay movement controlled by Fusion;
- use animations as visual representation;
- disable Root Motion unless the project has a deliberate synchronized Root Motion architecture.
Multiple Animator Layers
Projects can extend the same patterns to:
- upper-body attack layers;
- additive aiming;
- weapon layers;
- emote layers;
- damage reactions.
Only synchronize the values required to reconstruct the visual result.
For example:
- movement speed;
- equipped weapon ID;
- attack counter;
- aim weight;
- stance state.
Recommended NetworkMecanimAnimator Workflow
- Prepare the animation clips.
- Create the Animator Controller.
- Add locomotion parameters and transitions.
- Add
NetworkMecanimAnimator. - Assign the Animator.
- Cache parameter hashes.
- Update movement values from
FixedUpdateNetwork(). - Buffer local one-frame input.
- Send triggers through
NetworkMecanimAnimator.SetTrigger. - Test with multiple clients.
Recommended Networked Property Workflow
- Identify the minimum state required for animation.
- Create Networked properties for that state.
- Let State Authority write the values.
- Buffer rendered-frame input until the next network tick.
- Represent repeated events with counters.
- Clear buffered requests after consumption.
- Read synchronized values from
Render(). - Update the Animator locally.
- Initialize event comparison values during spawn.
- Add cooldown and validation for gameplay actions.
Key Concepts
| Concept | Description |
|---|---|
NetworkMecanimAnimator |
Fusion component for synchronizing Unity Animator parameters. |
| Animator parameter | Float, boolean, integer, or trigger that drives animation state. |
| Blend Tree | Animator state that blends multiple clips using a parameter. |
FixedUpdateNetwork() |
Tick-based Fusion simulation callback. |
Render() |
Unity presentation callback for displaying synchronized state. |
[Networked] |
Declares replicated Fusion state. |
| Attack counter | Incrementing Networked value used to represent repeated events. |
| Buffered input | Local input stored until a Fusion tick consumes it. |
| State Authority | Peer allowed to write the player object’s Networked properties. |
| Parameter hash | Cached integer identifier for an Animator parameter. |
| Tick-accurate animation | Animation state aligned precisely with simulation ticks. |
TickTimer |
Fusion timer suitable for synchronized cooldowns and durations. |
Best Practices
Use this checklist when synchronizing Fusion animations:
- Keep gameplay state separate from Unity Animator state.
- Use
NetworkMecanimAnimatorfor fast setup and prototypes. - Use Networked properties when explicit control is required.
- Synchronize only the values needed by remote clients.
- Let State Authority write animation-related Networked state.
- Update visual Animator parameters from
Render(). - Buffer one-frame local input before consuming it in
FixedUpdateNetwork(). - Clear buffered actions after they are processed.
- Use counters for repeated one-shot events.
- Initialize local counter tracking when the object spawns.
- Cache Animator parameter hashes.
- Remove vertical velocity when calculating horizontal locomotion speed.
- Add gameplay cooldowns independently from animation transitions.
- Test all animation states from local and proxy perspectives.
- Use tick-based animation systems for competitive frame-sensitive gameplay.
Common Pitfalls
| Pitfall | Why It Is a Problem |
|---|---|
Reading GetKeyDown only in FixedUpdateNetwork() |
The one-frame input can be missed between network ticks. |
Calling Animator.SetTrigger only locally |
Remote peers do not receive the event. |
| Letting proxy players read local input | Remote player objects may react to the wrong client’s device input. |
| Using a boolean for repeated attacks | Repeated identical events may not produce a replicated change. |
| Not clearing the attack request | The attack can trigger every network tick. |
| Updating Animator state as authoritative gameplay logic | Animator timing is presentation-driven and frame-dependent. |
| Synchronizing every Animator parameter | Can add unnecessary network state and coupling. |
Updating Networked properties from Render() |
Render() is intended for presentation, not authoritative state changes. |
| Forgetting to initialize the last attack counter | A previous event can replay when the object spawns. |
| Using animation duration as the only attack cooldown | Visual state should not be the sole gameplay authority. |
| Enabling Root Motion without a network architecture for it | Animation and network movement can conflict. |
| Using regular Mecanim sync for tick-critical hitboxes | Visual animation may not align precisely across simulation ticks. |
Summary
Fusion provides two practical approaches for synchronizing Unity animations.
NetworkMecanimAnimator offers a fast setup for synchronizing Animator parameters and triggers with minimal code.
Manual Networked properties provide more explicit control. State Authority writes values such as movement speed and attack counters during FixedUpdateNetwork(), while every peer applies those values to its local Animator from Render().
For ordinary idle, movement, attack, and co-op animation requirements, either approach can work. For competitive gameplay where hitboxes and animation phases must align with exact simulation ticks, use a tick-accurate animation architecture.
Last updated on
Back to top- Overview
- Video Timeline
- Project Setup
- Character Prefab
- Preparing Animation Clips
- Creating the Animator Controller
- Animator Parameters
- Approach 1: NetworkMecanimAnimator
- NetworkMecanimAnimator Setup
- PlayerAnimatorNMA
- Caching References
- Calculating Movement Speed
- Authority and Animation Input
- Attack Animation Setup
- Capturing Attack Input
- Consuming the Attack Request
- Why Use NetworkMecanimAnimator.SetTrigger?
- Testing NetworkMecanimAnimator
- Advantages of NetworkMecanimAnimator
- Limitations of NetworkMecanimAnimator
- Approach 2: Networked Properties
- Separating State from Presentation
- Networked Speed
- Updating the Animator from Render
- Synchronizing an Attack Event
- Why Use a Counter Instead of a Boolean?
- Detecting Attack Changes
- Initializing the Local Counter
- Full Manual Synchronization Example
- Preventing Attack Spam
- Attack Cooldown
- Comparing Both Approaches
- When to Use NetworkMecanimAnimator
- When to Use Networked Properties
- Animation State vs Gameplay State
- Tick-Accurate Animations
- Tick-Accurate Combat
- Render Method
- FixedUpdateNetwork Method
- Float Synchronization Considerations
- State-Based Locomotion Alternative
- Testing
- Late Join Behavior
- Animator Transition Configuration
- Root Motion
- Multiple Animator Layers
- Recommended NetworkMecanimAnimator Workflow
- Recommended Networked Property Workflow
- Key Concepts
- Best Practices
- Common Pitfalls
- Summary