// 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;
}
/************************************************************************************************************************/
}
}