예제 #1
0
        public static void RemoveChild(AnimancerState state, IList <AnimancerState> states)
        {
            var index = state.Index;

            if (index < 0)
            {
                throw new InvalidOperationException(
                          "Tried to remove a child state that did not actually have a Index assigned");
            }

            if (index > states.Count)
            {
                throw new IndexOutOfRangeException(
                          "state.Index (" + state.Index + ") is outside the collection of states (count " + states.Count + ")");
            }

            if (states[state.Index] != state)
            {
                throw new InvalidOperationException(
                          "Tried to remove a child state that was not actually connected to its port on " + state.Parent + ":" +
                          "\n    Port: " + state.Index +
                          "\n    Connected Child: " + states[state.Index] +
                          "\n    Disconnecting Child: " + state);
            }
        }
예제 #2
0
        /// <summary>
        /// Stops all other animations, plays the `state`, and returns it.
        /// <para></para>
        /// The animation will continue playing from its current <see cref="AnimancerState.Time"/>.
        /// If you wish to force it back to the start, you can simply set the `state`s time to 0.
        /// </summary>
        public AnimancerState Play(AnimancerState state)
        {
            Validate.Root(state, Root);

            if (TargetWeight != 1)
            {
                Weight = 1;
            }

            AddChild(state);

            CurrentState = state;

            state.Play();

            var count = States.Count;

            for (int i = 0; i < count; i++)
            {
                var otherState = States[i];
                if (otherState != state)
                {
                    otherState.Stop();
                }
            }

            return(state);
        }
예제 #3
0
        /************************************************************************************************************************/

        /// <summary>
        /// Sets the <see cref="CurrentState"/> and <see cref="CurrentEvent"/> then invokes the <see cref="callback"/>.
        /// </summary>
        /// <remarks>This method catches and logs any exception thrown by the <see cref="callback"/>.</remarks>
        /// <exception cref="NullReferenceException">The <see cref="callback"/> is null.</exception>
        public void Invoke(AnimancerState state)
        {
#if UNITY_ASSERTIONS
            if (IsNullOrDummy(callback))
            {
                OptionalWarning.UselessEvent.Log(
                    $"An {nameof(AnimancerEvent)} that does nothing was invoked." +
                    " Most likely it was not configured correctly." +
                    " Unused events should be removed to avoid wasting performance checking and invoking them.",
                    state?.Root?.Component);
            }
#endif

            var previousState = _CurrentState;
            var previousEvent = _CurrentEvent;

            _CurrentState = state;
            _CurrentEvent = this;

            try
            {
                callback();
            }
            catch (Exception exception)
            {
                Debug.LogException(exception, state?.Root?.Component as Object);
            }

            _CurrentState = previousState;
            _CurrentEvent = previousEvent;
        }
예제 #4
0
        /************************************************************************************************************************/

        /// <summary>
        /// Manipulates the other parameters according to the `mode`.
        /// </summary>
        private void EvaluateFadeMode(FadeMode mode, ref AnimancerState state, ref float fadeDuration, out bool isFixedDuration)
        {
            switch (mode)
            {
            case FadeMode.FixedSpeed:
                fadeDuration   *= Mathf.Abs(1 - state.Weight);
                isFixedDuration = false;
                break;

            case FadeMode.FixedDuration:
                isFixedDuration = true;
                break;

            case FadeMode.FromStart:
            {
                var previousState = state;
                state = GetOrCreateWeightlessState(state);
                if (previousState != state)
                {
                    var previousLayer = previousState.Layer;
                    if (previousLayer != this && previousLayer.CurrentState == previousState)
                    {
                        previousLayer.StartFade(0, fadeDuration);
                    }
                }
                isFixedDuration = false;
                break;
            }

            case FadeMode.NormalizedSpeed:
                fadeDuration   *= Mathf.Abs(1 - state.Weight) * state.Length;
                isFixedDuration = false;
                break;

            case FadeMode.NormalizedDuration:
                fadeDuration   *= state.Length;
                isFixedDuration = true;
                break;

            case FadeMode.NormalizedFromStart:
            {
                var previousState = state;
                state         = GetOrCreateWeightlessState(state);
                fadeDuration *= state.Length;
                if (previousState != state)
                {
                    var previousLayer = previousState.Layer;
                    if (previousLayer != this && previousLayer.CurrentState == previousState)
                    {
                        previousLayer.StartFade(0, fadeDuration);
                    }
                }
                isFixedDuration = false;
                break;
            }

            default:
                throw new ArgumentException("Invalid FadeMode: " + mode, "mode");
            }
        }
예제 #5
0
파일: Validate.cs 프로젝트: malering/ET
        public static void AssertCanRemoveChild(AnimancerState state, IList <AnimancerState> states)
        {
#if UNITY_ASSERTIONS
            var index = state.Index;

            if (index < 0)
            {
                throw new InvalidOperationException(
                          $"Cannot remove a child state that did not have an {nameof(state.Index)} assigned");
            }

            if (index > states.Count)
            {
                throw new IndexOutOfRangeException(
                          $"{nameof(AnimancerState)}.{nameof(state.Index)} ({state.Index})" +
                          $" is outside the collection of states (count {states.Count})");
            }

            if (states[state.Index] != state)
            {
                throw new InvalidOperationException(
                          $"Cannot remove a child state that was not actually connected to its port on {state.Parent}:" +
                          $"\n• Port: {state.Index}" +
                          $"\n• Connected Child: {AnimancerUtilities.ToStringOrNull(states[state.Index])}" +
                          $"\n• Disconnecting Child: {AnimancerUtilities.ToStringOrNull(state)}");
            }
#endif
        }
예제 #6
0
        /************************************************************************************************************************/

        /// <summary>
        /// If the <see cref="AnimancerState.Clip"/> and <see cref="AnimancerNode.Weight"/> match the
        /// <see cref="AnimationEvent"/>, this method invokes the <see cref="AnimancerEvent.Sequence.OnEnd"/> callback
        /// and returns true.
        /// </summary>
        private static bool TryInvokeOnEndEvent(AnimancerState state, AnimationEvent animationEvent)
        {
            if (state.Weight != animationEvent.animatorClipInfo.weight ||
                state.Clip != animationEvent.animatorClipInfo.clip ||
                !state.HasEvents)
            {
                return(false);
            }

            var endEvent = state.Events.endEvent;

            if (endEvent.callback != null)
            {
                Debug.Assert(CurrentEvent == null, $"Recursive call to {nameof(TryInvokeOnEndEvent)} detected");

                try
                {
                    CurrentEvent = animationEvent;
                    endEvent.Invoke(state);
                }
                finally
                {
                    CurrentEvent = null;
                }
            }

            return(true);
        }
예제 #7
0
        public static void AssertCanRemoveChild(AnimancerState state, IList <AnimancerState> states)
        {
#if UNITY_ASSERTIONS
            var index = state.Index;

            if (index < 0)
            {
                throw new InvalidOperationException(
                          "Cannot remove a child state that did not have an Index assigned");
            }

            if (index > states.Count)
            {
                throw new IndexOutOfRangeException(
                          "AnimancerState.Index (" + state.Index + ") is outside the collection of states (count " + states.Count + ")");
            }

            if (states[state.Index] != state)
            {
                throw new InvalidOperationException(
                          "Cannot remove a child state that was not actually connected to its port on " + state.Parent + ":" +
                          "\n    Port: " + state.Index +
                          "\n    Connected Child: " + AnimancerUtilities.ToStringOrNull(states[state.Index]) +
                          "\n    Disconnecting Child: " + AnimancerUtilities.ToStringOrNull(state));
            }
#endif
        }
예제 #8
0
        /************************************************************************************************************************/

        /// <summary>Disconnects the `state` from this layer at its <see cref="AnimancerNode.Index"/>.</summary>
        protected internal override void OnRemoveChild(AnimancerState state)
        {
            var index = state.Index;

            Validate.RemoveChild(state, States);

            if (_Playable.GetInput(index).IsValid())
            {
                Root._Graph.Disconnect(_Playable, index);
            }

            // Swap the last state into the place of the one that was just removed.
            var lastPort = States.Count - 1;

            if (index < lastPort)
            {
                state = States[lastPort];
                state.DisconnectFromGraph();

                States[index] = state;
                state.Index   = index;

                if (KeepChildrenConnected || state.Weight != 0)
                {
                    state.ConnectToGraph();
                }
            }

            States.RemoveAt(lastPort);
            _Playable.SetInputCount(lastPort);
        }
예제 #9
0
        /************************************************************************************************************************/

        /// <summary>
        /// Throws an <see cref="ArgumentException"/> if the <see cref="AnimancerState.Parent"/> is not this
        /// <see cref="AnimancerLayer"/>.
        /// </summary>
        /// <exception cref="ArgumentException"/>
        public void ValidateState(AnimancerState state)
        {
            if (state.Parent != this)
            {
                throw new ArgumentException("AnimancerState.Parent mismatch:" +
                                            " you are attempting to use a state in an AnimancerLayer that isn't it's parent.");
            }
        }
예제 #10
0
 public static void Parent(AnimancerState state, AnimancerNode parent)
 {
     if (state.Parent != parent)
     {
         throw new ArgumentException("AnimancerState.Parent mismatch:" +
                                     " you are attempting to use a state in an AnimancerLayer that is not it's parent.");
     }
 }
예제 #11
0
        /// <summary>
        /// Sets the <see cref="Source"/> and <see cref="Callback"/>.
        /// </summary>
        public void Set(AnimancerState source, Action <AnimationEvent> callback)
        {
            Source   = source;
            Callback = callback;

#if UNITY_EDITOR
            ValidateSourceHasCorrectEvent();
#endif
        }
예제 #12
0
        /// <summary>
        /// Returns the value of the <see cref="Curve"/> at the current <see cref="AnimancerState.Time"/>.
        /// </summary>
        public float Evaluate(AnimancerState state)
        {
            if (state == null)
            {
                return(0);
            }

            return(Evaluate(state.Time % state.Length));
        }
예제 #13
0
            /// <summary>[Internal] Removes the `state` from this dictionary (the opposite of <see cref="Register"/>).</summary>
            internal void Unregister(AnimancerState state)
            {
                var key = state._Key;

                if (key != null)
                {
                    States.Remove(key);
                }
            }
예제 #14
0
            /// <summary>[Internal] Removes the `state` from this dictionary (the opposite of <see cref="Register"/>).</summary>
            internal void Unregister(AnimancerState state)
            {
                if (state._Key == null)
                {
                    return;
                }

                States.Remove(state._Key);
                state._Key = null;
            }
예제 #15
0
            /// <summary>
            /// If a state is registered with the `key`, this method outputs it as the `state` and returns true. Otherwise
            /// `state` is set to null and this method returns false.
            /// </summary>
            public bool TryGet(object key, out AnimancerState state)
            {
                if (key == null)
                {
                    state = null;
                    return(false);
                }

                return(States.TryGetValue(key, out state));
            }
예제 #16
0
            /************************************************************************************************************************/

            /// <summary>
            /// Calls <see cref="GetKey"/> then passes the key to
            /// <see cref="TryGet(object, out AnimancerState)"/> and returns the result.
            /// </summary>
            public bool TryGet(AnimationClip clip, out AnimancerState state)
            {
                if (clip == null)
                {
                    state = null;
                    return(false);
                }

                return(TryGet(Root.GetKey(clip), out state));
            }
예제 #17
0
            /// <summary>
            /// Passes the <see cref="IHasKey.Key"/> into <see cref="TryGet(object, out AnimancerState)"/>
            /// and returns the result.
            /// </summary>
            public bool TryGet(IHasKey hasKey, out AnimancerState state)
            {
                if (hasKey == null)
                {
                    state = null;
                    return(false);
                }

                return(TryGet(hasKey.Key, out state));
            }
예제 #18
0
        /************************************************************************************************************************/

        /// <summary>
        /// Initialises this mixer with the specified number of ports which can be filled individually by <see cref="CreateState"/>.
        /// </summary>
        public virtual void Initialise(int portCount)
        {
            if (portCount <= 1)
            {
                Debug.LogWarning(GetType() + " is being initialised with capacity <= 1. The purpose of a mixer is to mix multiple clips.");
            }

            _Playable.SetInputCount(portCount);
            States = new AnimancerState[portCount];
        }
예제 #19
0
            /************************************************************************************************************************/

            /// <summary>[<see cref="ITransition"/>]
            /// Called by <see cref="AnimancerPlayable.Play(ITransition)"/> to set the <see cref="BaseState"/>
            /// and apply any other modifications to the `state`.
            /// </summary>
            /// <remarks>
            /// This method also clears the <see cref="State"/> if necessary, so it will re-cast the
            /// <see cref="BaseState"/> when it gets accessed again.
            /// </remarks>
            public virtual void Apply(AnimancerState state)
            {
                state.Events = _Events;

                BaseState = state;

                if (_State != state)
                {
                    _State = null;
                }
            }
예제 #20
0
        /************************************************************************************************************************/

        /// <summary>
        /// Constructs a new <see cref="AnimationEventReceiver"/> and sets the <see cref="Source"/> and
        /// <see cref="Callback"/>.
        /// </summary>
        public AnimationEventReceiver(AnimancerState source, Action <AnimationEvent> callback)
        {
            _Source   = source;
            _SourceID = source != null ? source.Layer.CommandCount : -1;

            Callback = callback;

#if UNITY_EDITOR
            FunctionName = null;
            ValidateSourceHasCorrectEvent();
#endif
        }
예제 #21
0
        /// <summary>
        /// Starts fading in the 'state' from the start over the course of the 'fadeDuration' while fading out all
        /// others in this layer. Returns the 'state'.
        /// <para></para>
        /// If the 'state' isn't currently at 0 <see cref="AnimancerState.Weight"/>, this method will actually fade it
        /// to 0 along with the others and create and return a new state with the same clip to fade to 1. This ensures
        /// that calling this method will always fade out from all current states and fade in from the start of the
        /// desired animation. States created for this purpose are cached so they can be reused in the future.
        /// <para></para>
        /// Calling this method repeatedly on subsequent frames will probably have undesirable effects; you most likely
        /// want to use <see cref="CrossFade"/> instead.
        /// <para></para>
        /// If this layer currently has 0 <see cref="Weight"/>, this method will instead start fading in the layer
        /// itself and simply <see cref="Play"/> the 'state'.
        /// <para></para>
        /// Animancer Lite only allows the default 'fadeDuration' (0.3 seconds) in a runtime build.
        /// </summary>
        /// <remarks>
        /// This can be useful when you want to repeat an action while the previous animation is still fading out.
        /// For example, if you play an 'Attack' animation, it ends and starts fading back to 'Idle', and while it is
        /// doing so you want to start another 'Attack'. The previous 'Attack' can't simply snap back to the start, so
        /// you can use this method to create a second 'Attack' state to fade in while the old one fades out.
        /// </remarks>
        public AnimancerState CrossFadeFromStart(AnimancerState state, float fadeDuration = AnimancerPlayable.DefaultFadeDuration)
        {
            if (Weight == 0)
            {
                return(Play(state));
            }

            if (Weight != 0 && state.Weight != 0)
            {
                var clip = state.Clip;

                if (clip == null)
                {
                    Debug.LogWarning("CrossFadeFromStart was called on a state which has no clip: " + state, state.MainObject);
                }
                else
                {
                    var layerIndex = state.LayerIndex;

                    // Get the default state registered with the clip.
                    state = Root.GetOrCreateState(clip, clip, layerIndex);

#if UNITY_EDITOR
                    int depth = 1;
#endif

                    // If that state isn't at 0 weight, get or create another state registered using the previous state as a key.
                    // Keep going through states in this manner until you find one at 0 weight.
                    while (state.Weight != 0)
                    {
                        // Explicitly cast the state to an object to avoid the overload that warns about using a state as a key.
                        state = Root.GetOrCreateState((object)state, clip, layerIndex);

#if UNITY_EDITOR
                        if (depth++ == maxCrossFadeFromStartDepth)
                        {
                            throw new ArgumentOutOfRangeException("depth", "CrossFadeFromStart has created " +
                                                                  maxCrossFadeFromStartDepth + " or more states for a single clip." +
                                                                  " This is most likely a result of calling the method repeatedly on consecutive frames." +
                                                                  " You probably just want to use CrossFade instead, but you can increase" +
                                                                  " AnimancerLayer.MaxCrossFadeFromStartDepth if necessary.");
                        }
#endif
                    }
                }
            }

            // Reset the time in case it wasn't already reset when the weight was previously set to 0.
            state.Time = 0;

            // Now that we have a state with 0 weight, start fading it in.
            return(CrossFade(state, fadeDuration));
        }
예제 #22
0
        /// <summary>
        /// If the `state` is not currently at 0 <see cref="AnimancerNode.Weight"/>, this method finds a copy of it
        /// which is at 0 or creates a new one.
        /// </summary>
        /// <exception cref="InvalidOperationException">Thrown if the <see cref="AnimancerState.Clip"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown if more states have been created for this <see cref="AnimancerState.Clip"/> than the
        /// <see cref="maxStateDepth"/> allows.
        /// </exception>
        public AnimancerState GetOrCreateWeightlessState(AnimancerState state)
        {
            if (state.Weight != 0)
            {
                var clip = state.Clip;
                if (clip == null)
                {
                    throw new InvalidOperationException(
                              "GetOrCreateWeightlessState was called on a state which has no clip: " + state);

                    // We could probably support any state type by giving them a Clone method, but that would take a
                    // lot of work for something that might never get used.
                }
                else
                {
                    // Get the default state registered with the clip.
                    if (state.Key as Object != clip)
                    {
                        state = Root.States.GetOrCreate(clip, clip);
                    }

#if UNITY_EDITOR
                    int depth = 0;
#endif

                    // If that state is not at 0 weight, get or create another state registered using the previous state as a key.
                    // Keep going through states in this manner until you find one at 0 weight.
                    while (state.Weight != 0)
                    {
                        // Explicitly cast the state to an object to avoid the overload that warns about using a state as a key.
                        state = Root.States.GetOrCreate((object)state, clip);

#if UNITY_EDITOR
                        if (++depth == maxStateDepth)
                        {
                            throw new ArgumentOutOfRangeException("depth", "GetOrCreateWeightlessState has created " +
                                                                  maxStateDepth + " or more states for a single clip." +
                                                                  " This is most likely a result of calling the method repeatedly on consecutive frames." +
                                                                  " You probably just want to use FadeMode.FixedSpeed instead, but you can increase" +
                                                                  " AnimancerLayer.maxStateDepth if necessary.");
                        }
#endif
                    }
                }
            }

            // Make sure it is on this layer and at time 0.
            AddChild(state);
            state.Time = 0;

            return(state);
        }
예제 #23
0
        /************************************************************************************************************************/

        /// <summary>
        /// Adds a new port and uses <see cref="AnimancerState.SetParent"/> to connect the `state` to it.
        /// </summary>
        public void AddChild(AnimancerState state)
        {
            if (state.Parent == this)
            {
                return;
            }

            var index = States.Count;

            States.Add(null);
            _Playable.SetInputCount(index + 1);
            state.SetParent(this, index);
        }
예제 #24
0
        /// <summary>
        /// Gather the current details of the <see cref="AnimancerNode.Root"/> and register this
        /// <see cref="CustomFade"/> to be updated by it so that it can replace the regular fade behaviour.
        /// </summary>
        protected void Apply(AnimancerState state)
        {
#if UNITY_ASSERTIONS
            Debug.Assert(state != null, "State is null.");
            Debug.Assert(state.IsValid, "State is not valid.");
            Debug.Assert(state.IsPlaying, "State is not playing.");
            Debug.Assert(state.LayerIndex >= 0, "State is not connected to a layer.");
            Debug.Assert(state.TargetWeight > 0, "State is not fading in.");

            var animancer = state.Root;
            Debug.Assert(animancer != null, $"{nameof(state)}.{nameof(state.Root)} is null.");

#if UNITY_EDITOR
            if (WarningType.CustomFadeBounds.IsEnabled())
            {
                if (CalculateWeight(0) != 0)
                {
                    WarningType.CustomFadeBounds.Log("CalculateWeight(0) != 0.", animancer.Component);
                }
                if (CalculateWeight(1) != 1)
                {
                    WarningType.CustomFadeBounds.Log("CalculateWeight(1) != 1.", animancer.Component);
                }
            }
#endif
#endif

            _FadeSpeed = state.FadeSpeed;
            if (_FadeSpeed == 0)
            {
                return;
            }

            _Time         = 0;
            _TargetState  = new StateWeight(state);
            _TargetLayer  = state.Layer;
            _CommandCount = _TargetLayer.CommandCount;

            OtherStates.Clear();
            for (int i = _TargetLayer.ChildCount - 1; i >= 0; i--)
            {
                var other = _TargetLayer.GetChild(i);
                other.FadeSpeed = 0;
                if (other != state && other.Weight != 0)
                {
                    OtherStates.Add(new StateWeight(other));
                }
            }

            state.Root.RequireUpdate(this);
        }
예제 #25
0
        /// <summary>
        /// Starts fading in the `state` over the course of the `fadeDuration` while fading out all others in this
        /// layer. Returns the `state`.
        /// <para></para>
        /// If the `state` was already playing and fading in with less time remaining than the `fadeDuration`, this
        /// method will allow it to complete the existing fade rather than starting a slower one.
        /// <para></para>
        /// If the layer currently has 0 <see cref="AnimancerNode.Weight"/>, this method will fade in the layer itself
        /// and simply <see cref="AnimancerState.Play"/> the `state`.
        /// <para></para>
        /// Animancer Lite only allows the default `fadeDuration` (0.25 seconds) in a runtime build.
        /// </summary>
        public AnimancerState Play(AnimancerState state, float fadeDuration, FadeMode mode = FadeMode.FixedSpeed)
        {
            Validate.Root(state, Root);

            if (fadeDuration <= 0 ||         // With no fade duration, Play immediately.
                (Index == 0 && Weight == 0)) // First animation on Layer 0 snap Weight to 1.
            {
                return(Play(state));
            }

            bool isFixedDuration;

            EvaluateFadeMode(mode, ref state, ref fadeDuration, out isFixedDuration);

            StartFade(1, fadeDuration);
            if (Weight == 0)
            {
                return(Play(state));
            }

            AddChild(state);

            CurrentState = state;

            // If the state is already playing or will finish fading in faster than this new fade,
            // continue the existing fade but still pretend it was restarted.
            if (state.IsPlaying && state.TargetWeight == 1 &&
                (state.Weight == 1 || state.FadeSpeed * fadeDuration > Math.Abs(1 - state.Weight)))
            {
                OnStartFade();
            }
            // Otherwise fade in the target state and fade out all others.
            else
            {
                state.IsPlaying = true;
                state.StartFade(1, fadeDuration);

                var count = States.Count;
                for (int i = 0; i < count; i++)
                {
                    var otherState = States[i];
                    if (otherState != state)
                    {
                        otherState.StartFade(0, fadeDuration);
                    }
                }
            }

            return(state);
        }
예제 #26
0
        /************************************************************************************************************************/

        /// <summary>
        /// Initialises the <see cref="Mixer"/> with two ports and connects two states to them for the specified clips
        /// at the specified thresholds (default 0 and 1).
        /// </summary>
        public void Initialise(AnimationClip clip0, AnimationClip clip1, float threshold0 = 0, float threshold1 = 1)
        {
            _Playable.SetInputCount(2);

            States = new AnimancerState[2];
            new ClipState(this, 0, clip0);
            new ClipState(this, 1, clip1);

            SetThresholds(new float[]
            {
                threshold0,
                threshold1,
            });
        }
예제 #27
0
        /************************************************************************************************************************/

        /// <summary>
        /// Adds a new port and uses <see cref="AnimancerState.SetParent"/> to connect the `state` to it.
        /// </summary>
        public void AddChild(AnimancerState state)
        {
            if (state.Parent == this)
            {
                return;
            }

            state.SetRoot(Root);

            var index = States.Count;

            States.Add(null);// OnAddChild will assign the state.
            _Playable.SetInputCount(index + 1);
            state.SetParent(this, index);
        }
예제 #28
0
            /************************************************************************************************************************/

            /// <summary>[Internal]
            /// Registers the `state` in this dictionary so the `key` can be used to get it later on using
            /// any of the lookup methods such as <see cref="this[object]"/>.
            /// </summary>
            /// <remarks>The `key` can be <c>null</c>.</remarks>
            internal void Register(object key, AnimancerState state)
            {
                if (key != null)
                {
#if UNITY_ASSERTIONS
                    if (state.Root != Root)
                    {
                        throw new ArgumentException(
                                  $"{nameof(StateDictionary)} cannot register a state with a different {nameof(Root)}: " + state);
                    }
#endif

                    States.Add(key, state);
                }

                state._Key = key;
            }
예제 #29
0
            /************************************************************************************************************************/

            /// <summary>
            /// Called by <see cref="AnimancerPlayable.Play(ITransition)"/> to apply the <see cref="Speed"/>
            /// and <see cref="NormalizedStartTime"/>.
            /// </summary>
            public override void Apply(AnimancerState state)
            {
                base.Apply(state);

                if (!float.IsNaN(_Speed))
                {
                    state.Speed = _Speed;
                }

                if (!float.IsNaN(_NormalizedStartTime))
                {
                    state.NormalizedTime = _NormalizedStartTime;
                }
                else if (state.Weight == 0)
                {
                    state.NormalizedTime = AnimancerEvent.Sequence.GetDefaultNormalizedStartTime(_Speed);
                }
            }
예제 #30
0
        /************************************************************************************************************************/

        /// <summary>
        /// Gathers the current details of the <see cref="AnimancerNode.Root"/> and register this
        /// <see cref="CustomFade"/> to be updated by it so that it can replace the regular fade behaviour.
        /// </summary>
        protected void Apply(AnimancerState state)
        {
            AnimancerUtilities.Assert(state.Parent != null, "Node is not connected to a layer.");

            Apply((AnimancerNode)state);

            var parent = state.Parent;

            for (int i = parent.ChildCount - 1; i >= 0; i--)
            {
                var other = parent.GetChild(i);
                if (other != state && other.FadeSpeed != 0)
                {
                    other.FadeSpeed = 0;
                    FadeOutNodes.Add(new NodeWeight(other));
                }
            }
        }