// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
using Animancer.Units;
using System;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Animancer
{
///
/// A serializable which can create a particular type of
/// when passed into .
///
///
/// Documentation:
///
/// Transitions
///
/// https://kybernetik.com.au/animancer/api/Animancer/Transition_1
[Serializable]
public abstract class Transition :
IPolymorphic,
ITransition,
ITransitionDetailed,
ITransitionWithEvents,
ICopyable>,
ICloneable>
where TState : AnimancerState
{
/************************************************************************************************************************/
[SerializeField]
[Tooltip(Strings.Tooltips.FadeDuration)]
[AnimationTime(AnimationTimeAttribute.Units.Seconds, Rule = Validate.Value.IsNotNegative)]
[DefaultFadeValue]
private float _FadeDuration = AnimancerGraph.DefaultFadeDuration;
///
/// []
/// Thrown when setting the value to a negative number.
public float FadeDuration
{
get => _FadeDuration;
set
{
if (value < 0)
throw new ArgumentOutOfRangeException(
nameof(value),
$"{nameof(FadeDuration)} must not be negative");
_FadeDuration = value;
}
}
/************************************************************************************************************************/
[SerializeField]
[Tooltip(Strings.Tooltips.OptionalSpeed)]
[AnimationSpeed(DisabledText = Strings.Tooltips.SpeedDisabled)]
[DefaultValue(1f, -1f)]
private float _Speed = 1;
/// []
/// Determines how fast the animation plays (1x = normal speed, 2x = double speed).
///
///
/// This sets the when this transition is played.
///
public float Speed
{
get => _Speed;
set => _Speed = value;
}
/************************************************************************************************************************/
///
/// Returns false unless overridden.
public virtual bool IsLooping => false;
///
public virtual float NormalizedStartTime
{
get => float.NaN;
set { }
}
///
public abstract float MaximumDuration { get; }
/************************************************************************************************************************/
[SerializeField, Tooltip(Strings.ProOnlyTag + "Events which will be triggered as the animation plays")]
private AnimancerEvent.Sequence.Serializable _Events;
///
/// This property returns the .
public virtual AnimancerEvent.Sequence Events
{
get => (_Events ??= new()).Events;
set => (_Events ??= new()).Events = value;
}
///
public ref AnimancerEvent.Sequence.Serializable SerializedEvents
=> ref _Events;
/************************************************************************************************************************/
///
/// The state that was created by this object. Specifically, this is the state that was most recently
/// passed into (usually by ).
///
/// You can use or
/// to get or create the state for a
/// specific object.
///
/// is simply a shorthand for casting this to .
///
public AnimancerState BaseState { get; private set; }
/************************************************************************************************************************/
private TState _State;
///
/// The state that was created by this object. Specifically, this is the state that was most recently
/// passed into (usually by ).
///
///
///
/// You can use or
///
/// to get or create the state for a specific object.
///
/// This property is shorthand for casting the to .
///
///
///
/// The is not actually a .
/// This should only happen if a different type of state was created by something else
/// and registered using the ,
/// causing this to pass that state into
/// instead of calling
/// to make the correct type of state.
///
public TState State
{
get => _State ??= (TState)BaseState;
protected set => BaseState = _State = value;
}
/************************************************************************************************************************/
///
/// Returns true unless overridden.
public virtual bool IsValid
=> true;
/// The which the created state will be registered with.
/// Returns this unless overridden.
public virtual object Key
=> this;
///
/// Returns unless overridden.
public virtual FadeMode FadeMode
=> FadeMode.FixedSpeed;
/************************************************************************************************************************/
///
public abstract TState CreateState();
///
AnimancerState ITransition.CreateState()
=> CreateAndInitializeState();
/// Calls and assigns the to the state.
public TState CreateAndInitializeState()
{
var state = CreateState();
AnimancerState.SetExpectFade(state, _FadeDuration);
State = state;
state.SharedEvents = _Events;
return state;
}
/************************************************************************************************************************/
///
public virtual void Apply(AnimancerState state)
{
if (_State != state)
{
_State = null;
BaseState = state;
}
if (!float.IsNaN(_Speed))
state.Speed = _Speed;
}
/************************************************************************************************************************/
/// Applies the `normalizedStartTime` to the `state`.
public static void ApplyNormalizedStartTime(AnimancerState state, float normalizedStartTime)
{
if (!float.IsNaN(normalizedStartTime))
state.NormalizedTime = normalizedStartTime;
else if (state.Weight == 0)
state.NormalizedTime = AnimancerEvent.Sequence.GetDefaultNormalizedStartTime(state.Speed);
}
/************************************************************************************************************************/
/// The that the created state will have.
public virtual Object MainObject { get; }
/// The display name of this transition.
public virtual string Name
{
get
{
var mainObject = MainObject;
return mainObject != null ? mainObject.name : null;
}
}
/// Returns the and type of this transition.
public override string ToString()
{
var type = GetType().FullName;
var name = Name;
return name is null
? type :
$"{name} ({type})";
}
/************************************************************************************************************************/
///
public abstract Transition Clone(CloneContext context);
///
public virtual void CopyFrom(Transition copyFrom, CloneContext context)
{
if (copyFrom == null)
{
_FadeDuration = AnimancerGraph.DefaultFadeDuration;
_Events = default;
_Speed = 1;
return;
}
_FadeDuration = copyFrom._FadeDuration;
_Speed = copyFrom._Speed;
_Events = copyFrom._Events.Clone();
}
/************************************************************************************************************************/
}
}