// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2023 Kybernetik // using System.Collections.Generic; using UnityEngine; namespace Animancer { /// A system for synchronizing the of certain animations. /// /// /// Store a in a field. /// Call any of the methods before playing a new animation. /// Then call any of the methods after playing the animation. /// /// Example: Character Controller -> Synchronization /// /// public enum AnimationType /// { /// None, /// Movement, /// } /// /// [SerializeField] private AnimancerComponent _Animancer; /// /// private readonly TimeSynchronizer<AnimationType> /// TimeSynchronizer = new TimeSynchronizer<AnimationType>(); /// /// public AnimancerState Play(AnimationClip clip, AnimationType type) /// { /// TimeSynchronizer.StoreTime(_Animancer); /// var state = _Animancer.Play(clip); /// TimeSynchronizer.SyncTime(state, type); /// return state; /// } /// /// /// https://kybernetik.com.au/animancer/api/Animancer/TimeSynchronizer_1 /// public class TimeSynchronizer { /************************************************************************************************************************/ /// The group that the current animation is in. public T CurrentGroup { get; set; } /// Should synchronization be applied when the is at its default value? /// This is false by default so that the default group represents "ungrouped". public bool SynchronizeDefaultGroup { get; set; } /// The stored . public double NormalizedTime { get; set; } /************************************************************************************************************************/ /// Creates a new . public TimeSynchronizer() { } /// Creates a new . public TimeSynchronizer(T group, bool synchronizeDefaultGroup = false) { CurrentGroup = group; SynchronizeDefaultGroup = synchronizeDefaultGroup; } /************************************************************************************************************************/ /// /// Stores the of the . /// public void StoreTime(AnimancerLayer layer) => StoreTime(layer.CurrentState); /// Stores the of the `state`. public void StoreTime(AnimancerState state) => NormalizedTime = state != null ? state.NormalizedTimeD : 0; /************************************************************************************************************************/ /// /// Applies the to the if the `group` /// matches the . /// public bool SyncTime(AnimancerLayer layer, T group) => SyncTime(layer.CurrentState, group, Time.deltaTime); /// /// Applies the to the if the `group` /// matches the . /// public bool SyncTime(AnimancerLayer layer, T group, float deltaTime) => SyncTime(layer.CurrentState, group, deltaTime); /// /// Applies the to the `state` if the `group` matches the /// . /// public bool SyncTime(AnimancerState state, T group) => SyncTime(state, group, Time.deltaTime); /// /// Applies the to the `state` if the `group` matches the /// . /// public bool SyncTime(AnimancerState state, T group, float deltaTime) { if (state == null || !EqualityComparer.Default.Equals(CurrentGroup, group) || (!SynchronizeDefaultGroup && EqualityComparer.Default.Equals(default, group))) { CurrentGroup = group; return false; } // Setting the Time forces it to stay at that value after the next animation update. // But we actually want it to keep playing, so we need to add deltaTime manually. state.TimeD = NormalizedTime * state.Length + deltaTime * state.EffectiveSpeed; return true; } /************************************************************************************************************************/ } }