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