In the docs for networking animation state changes, the examples use a command to broadcast that a trigger should be fired. I was originally using this method in my implementation but I’ve just refactored it to using a [sync]
on an int
, since my “behavior” for animations is just a state machine anyways, so I’m able to transition the state on the int being sync’d just as well as reacting to a command.
An advantage of this approach is that the sync
annotation is less likely to be misconfigured, since I don’t need to go into the Coherence Sync config and ensure that my command method is configured to be networked, I can just slap this decorator on the property and be done with it.
Is there any reason not to use a sync
representing a “state” (an enum) in this way? My only thought on why you might not want to do this is that it could be less performant since presumably now the SDK has to monitor the value explicitely rather than just send a command on demand.
Here’s my full script for further context:
public class UnitAnimationBehavior : MonoBehaviour
{
private class AnimationStateMachine : AbstractObservableMachine<AnimationBehaviorStates>
{
public AnimationStateMachine(AnimationBehaviorStates initialState) : base(initialState)
{}
public void Transition(AnimationBehaviorStates s) { TransitionInternalState(s); }
}
private static readonly int AttackTrigger = Animator.StringToHash("Attack");
private static readonly int DeathTrigger = Animator.StringToHash("Death");
private static readonly int MovementTrigger = Animator.StringToHash("Movement");
private Animator _animator;
private AnimationStateMachine _machine;
private CoherenceSync _coherenceSync;
[Sync]
[OnValueSynced(nameof(OnBehaviorStateValueSync))]
public int iNetBehaviorState = (int)AnimationBehaviorStates.Idle;
void Awake()
{
_coherenceSync = GetComponent<CoherenceSync>();
_machine = new AnimationStateMachine(AnimationBehaviorStates.Idle);
_animator = GetComponent<Animator>();
// Exit transitions
_machine.OnStateExit(AnimationBehaviorStates.Harvesting, () => _animator.ResetTrigger(AttackTrigger));
// more transitions not shown...
// Enter transitions
_machine.OnStateEnter(AnimationBehaviorStates.Harvesting, () => _animator.SetTrigger(AttackTrigger));
// more transitions not shown...
}
public void OnBehaviorStateValueSync(int oldValue, int newValue)
{
this.LogLog($"{(AnimationBehaviorStates)oldValue} -> {(AnimationBehaviorStates)newValue}");
TransitionState((AnimationBehaviorStates)newValue);
}
public void TransitionState(AnimationBehaviorStates nextState)
{
_machine.Transition(nextState);
AuthorityHelper.DoIfStateAuthority(_coherenceSync, () =>
{
iNetBehaviorState = (int)nextState;
});
}
}