Esempio n. 1
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(AnimancerNode node)
        {
#if UNITY_ASSERTIONS
            AnimancerUtilities.Assert(node != null, "Node is null.");
            AnimancerUtilities.Assert(node.IsValid, "Node is not valid.");
            AnimancerUtilities.Assert(node.FadeSpeed != 0, $"Node is not fading ({nameof(node.FadeSpeed)} is 0).");

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

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

            _Time         = 0;
            _Target       = new NodeWeight(node);
            _FadeSpeed    = node.FadeSpeed;
            _Layer        = node.Layer;
            _CommandCount = _Layer.CommandCount;

            node.FadeSpeed = 0;

            FadeOutNodes.Clear();

            node.Root.RequirePreUpdate(this);
        }
Esempio n. 2
0
        /************************************************************************************************************************/

        /// <summary>Returns a spare <see cref="HashSet{T}"/> if there are any, or creates a new one.</summary>
        /// <remarks>Remember to <see cref="Release{T}(HashSet{T})"/> it when you are done.</remarks>
        public static HashSet <T> AcquireSet <T>()
        {
            var set = ObjectPool <HashSet <T> > .Acquire();

            AnimancerUtilities.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError);
            return(set);
        }
Esempio n. 3
0
            /************************************************************************************************************************/

            /// <summary>
            /// Creates a new <see cref="ObjectPool{T}.Disposable"/> and calls <see cref="ObjectPool{T}.Acquire"/> to set the
            /// <see cref="ObjectPool{T}.Disposable.Item"/> and `item`.
            /// </summary>
            public static ObjectPool <HashSet <T> > .Disposable AcquireSet <T>(out HashSet <T> set)
            {
                var disposable = new ObjectPool <HashSet <T> > .Disposable(out set, onRelease : (s) => s.Clear());

                AnimancerUtilities.Assert(set.Count == 0, "A pooled set is not empty." + NotClearError);
                return(disposable);
            }
Esempio n. 4
0
        /************************************************************************************************************************/

        /// <summary>Returns a spare <see cref="List{T}"/> if there are any, or creates a new one.</summary>
        /// <remarks>Remember to <see cref="Release{T}(List{T})"/> it when you are done.</remarks>
        public static List <T> AcquireList <T>()
        {
            var list = ObjectPool <List <T> > .Acquire();

            AnimancerUtilities.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError);
            return(list);
        }
Esempio n. 5
0
        /************************************************************************************************************************/

        /// <summary>Returns a spare <see cref="StringBuilder"/> if there are any, or creates a new one.</summary>
        /// <remarks>Remember to <see cref="Release(StringBuilder)"/> it when you are done.</remarks>
        public static StringBuilder AcquireStringBuilder()
        {
            var builder = ObjectPool <StringBuilder> .Acquire();

            AnimancerUtilities.Assert(builder.Length == 0, $"A pooled {nameof(StringBuilder)} is not empty." + NotClearError);
            return(builder);
        }
Esempio n. 6
0
            /************************************************************************************************************************/

            /// <summary>
            /// Creates a new <see cref="ObjectPool{T}.Disposable"/> and calls <see cref="ObjectPool{T}.Acquire"/> to set the
            /// <see cref="ObjectPool{T}.Disposable.Item"/> and `item`.
            /// </summary>
            public static ObjectPool <List <T> > .Disposable AcquireList <T>(out List <T> list)
            {
                var disposable = new ObjectPool <List <T> > .Disposable(out list, onRelease : (l) => l.Clear());

                AnimancerUtilities.Assert(list.Count == 0, "A pooled list is not empty." + NotClearError);
                return(disposable);
            }
Esempio n. 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
        }
Esempio n. 8
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 {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
        }
        /************************************************************************************************************************/

        /// <summary>Sets the animation associated with the specified `direction`.</summary>
        public void SetClip(Direction direction, AnimationClip clip)
        {
            switch (direction)
            {
            case Direction.Up: SetUp(clip); break;

            case Direction.Right: SetRight(clip); break;

            case Direction.Down: SetDown(clip); break;

            case Direction.Left: SetLeft(clip); break;

            case Direction.UpRight: _UpRight = clip; break;

            case Direction.DownRight: _DownRight = clip; break;

            case Direction.DownLeft: _DownLeft = clip; break;

            case Direction.UpLeft: _UpLeft = clip; break;

            default: throw new ArgumentException($"Unsupported {nameof(Direction)}: {direction}");
            }

            AnimancerUtilities.SetDirty(this);
        }
Esempio n. 10
0
            /************************************************************************************************************************/

            /// <summary>
            /// Recalculates the <see cref="CurrentSpeeds"/> depending on the <see cref="AnimationClip.length"/> of
            /// their animations so that they all take the same amount of time to play fully.
            /// </summary>
            private static void NormalizeDurations(SerializedProperty property)
            {
                var speedCount = CurrentSpeeds.arraySize;

                var lengths = new float[CurrentAnimations.arraySize];

                if (lengths.Length <= 1)
                {
                    return;
                }

                int   nonZeroLengths = 0;
                float totalLength    = 0;
                float totalSpeed     = 0;

                for (int i = 0; i < lengths.Length; i++)
                {
                    var state = CurrentAnimations.GetArrayElementAtIndex(i).objectReferenceValue;
                    if (AnimancerUtilities.TryGetLength(state, out var length) &&
                        length > 0)
                    {
                        nonZeroLengths++;
                        totalLength += length;
                        lengths[i]   = length;

                        if (speedCount > 0)
                        {
                            totalSpeed += CurrentSpeeds.GetArrayElementAtIndex(i).floatValue;
                        }
                    }
                }

                if (nonZeroLengths == 0)
                {
                    return;
                }

                var averageLength = totalLength / nonZeroLengths;
                var averageSpeed  = speedCount > 0 ? totalSpeed / nonZeroLengths : 1;

                CurrentSpeeds.arraySize = lengths.Length;
                InitializeSpeeds(speedCount);

                for (int i = 0; i < lengths.Length; i++)
                {
                    if (lengths[i] == 0)
                    {
                        continue;
                    }

                    CurrentSpeeds.GetArrayElementAtIndex(i).floatValue = averageSpeed * lengths[i] / averageLength;
                }

                TryCollapseArrays();
            }
Esempio n. 11
0
        /************************************************************************************************************************/

        /// <summary>
        /// Called by <see cref="AnimancerNode.AppendDescription"/> to append the details of this node.
        /// </summary>
        protected override void AppendDetails(StringBuilder text, string delimiter)
        {
            base.AppendDetails(text, delimiter);

            text.Append(delimiter).Append("CurrentState: ").Append(CurrentState);
            text.Append(delimiter).Append("CommandCount: ").Append(CommandCount);
            text.Append(delimiter).Append("IsAdditive: ").Append(IsAdditive);

#if UNITY_EDITOR
            text.Append(delimiter).Append("AvatarMask: ").Append(AnimancerUtilities.ToStringOrNull(_Mask));
#endif
        }
Esempio n. 12
0
        /************************************************************************************************************************/

        /// <summary>
        /// Registers the `callback` to be triggered when the <see cref="AnimancerNode.EffectiveWeight"/> becomes 0.
        /// </summary>
        /// <remarks>
        /// The <see cref="AnimancerNode.EffectiveWeight"/> is only checked at the end of the animation update so if it
        /// is set to 0 then back to a higher number before the next update, the callback will not be triggered.
        /// </remarks>
        public static void Register(AnimancerNode node, Action callback)
        {
#if UNITY_ASSERTIONS
            AnimancerUtilities.Assert(node != null, "Node is null.");
            AnimancerUtilities.Assert(node.IsValid, "Node is not valid.");
#endif

            var exit = ObjectPool.Acquire <ExitEvent>();
            exit._Callback = callback;
            exit._Node     = node;
            node.Root.RequirePostUpdate(exit);
        }
        /************************************************************************************************************************/

        /// <summary>Sets the animation associated with the specified `direction`.</summary>
        public void SetClip(Direction direction, AnimationClip clip)
        {
            switch (direction)
            {
            case Direction.Up: _Up = clip; break;

            case Direction.Right: _Right = clip; break;

            case Direction.Down: _Down = clip; break;

            case Direction.Left: _Left = clip; break;

            default: throw new ArgumentException("Unhandled direction: " + direction);
            }

            AnimancerUtilities.SetDirty(this);
        }
Esempio n. 14
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));
                }
            }
        }
Esempio n. 15
0
            /************************************************************************************************************************/
            #region Threshold Calculation Functions
            /************************************************************************************************************************/

            /// <inheritdoc/>
            protected override void AddThresholdFunctionsToMenu(GenericMenu menu)
            {
                AddCalculateThresholdsFunction(menu, "From Velocity/XY", (state, threshold) =>
                {
                    if (AnimancerUtilities.TryGetAverageVelocity(state, out var velocity))
                    {
                        return(new Vector2(velocity.x, velocity.y));
                    }
                    else
                    {
                        return(new Vector2(float.NaN, float.NaN));
                    }
                });

                AddCalculateThresholdsFunction(menu, "From Velocity/XZ", (state, threshold) =>
                {
                    if (AnimancerUtilities.TryGetAverageVelocity(state, out var velocity))
                    {
                        return(new Vector2(velocity.x, velocity.z));
                    }
                    else
                    {
                        return(new Vector2(float.NaN, float.NaN));
                    }
                });

                AddCalculateThresholdsFunctionPerAxis(menu, "From Speed",
                                                      (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.magnitude : float.NaN);
                AddCalculateThresholdsFunctionPerAxis(menu, "From Velocity X",
                                                      (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.x : float.NaN);
                AddCalculateThresholdsFunctionPerAxis(menu, "From Velocity Y",
                                                      (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.y : float.NaN);
                AddCalculateThresholdsFunctionPerAxis(menu, "From Velocity Z",
                                                      (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.z : float.NaN);
                AddCalculateThresholdsFunctionPerAxis(menu, "From Angular Speed (Rad)",
                                                      (state, threshold) => AnimancerUtilities.TryGetAverageAngularSpeed(state, out var speed) ? speed : float.NaN);
                AddCalculateThresholdsFunctionPerAxis(menu, "From Angular Speed (Deg)",
                                                      (state, threshold) => AnimancerUtilities.TryGetAverageAngularSpeed(state, out var speed) ? speed * Mathf.Rad2Deg : float.NaN);

                AddPropertyModifierFunction(menu, "Initialize 4 Directions", Initialize4Directions);
                AddPropertyModifierFunction(menu, "Initialize 8 Directions", Initialize8Directions);
            }
            /************************************************************************************************************************/

            /// <inheritdoc/>
            protected override void AddThresholdFunctionsToMenu(UnityEditor.GenericMenu menu)
            {
                const string EvenlySpaced = "Evenly Spaced";

                var count = CurrentThresholds.arraySize;

                if (count <= 1)
                {
                    menu.AddDisabledItem(new GUIContent(EvenlySpaced));
                }
                else
                {
                    var first = CurrentThresholds.GetArrayElementAtIndex(0).floatValue;
                    var last  = CurrentThresholds.GetArrayElementAtIndex(count - 1).floatValue;

                    if (last == first)
                    {
                        last++;
                    }

                    AddPropertyModifierFunction(menu, $"{EvenlySpaced} ({first} to {last})", (_) =>
                    {
                        for (int i = 0; i < count; i++)
                        {
                            CurrentThresholds.GetArrayElementAtIndex(i).floatValue = Mathf.Lerp(first, last, i / (float)(count - 1));
                        }
                    });
                }

                AddCalculateThresholdsFunction(menu, "From Speed",
                                               (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.magnitude : float.NaN);
                AddCalculateThresholdsFunction(menu, "From Velocity X",
                                               (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.x : float.NaN);
                AddCalculateThresholdsFunction(menu, "From Velocity Y",
                                               (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.y : float.NaN);
                AddCalculateThresholdsFunction(menu, "From Velocity Z",
                                               (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.z : float.NaN);
                AddCalculateThresholdsFunction(menu, "From Angular Speed (Rad)",
                                               (state, threshold) => AnimancerUtilities.TryGetAverageAngularSpeed(state, out var speed) ? speed : float.NaN);
                AddCalculateThresholdsFunction(menu, "From Angular Speed (Deg)",
                                               (state, threshold) => AnimancerUtilities.TryGetAverageAngularSpeed(state, out var speed) ? speed * Mathf.Rad2Deg : float.NaN);
            }
        /************************************************************************************************************************/
        #endregion
        /************************************************************************************************************************/
        #region Initialisation //初始
        /************************************************************************************************************************/

#if UNITY_EDITOR
        /// <summary>[仅在编辑模式]
        /// 当这个组件第一次被添加时(在编辑模式下),以及当重置命令从它的上下文菜单中执行时,由Unity编辑器调用
        /// <para></para>
        /// 如果已初始化,则销毁播放模式的数据
        /// 在此对象或其子对象或父对象上搜索<see cref="UnityEngine.Animator"/>
        /// 删除 <see cref="Animator.runtimeAnimatorController"/> 如果找到的话
        /// <para></para>
        /// 此方法还可以防止将此组件的多个副本添加到单个对象。这样做将立即销毁新字段并更改旧字段的类型以匹配新字段,
        /// 从而允许您更改类型而不会丢失它们共享的任何序列化字段的值.
        /// </summary>
        protected virtual void Reset()
        {
            OnDestroy();

            _Animator = Editor.AnimancerEditorUtilities.GetComponentInHierarchy <Animator>(gameObject);//获取层次结构中的组件

            if (_Animator != null)
            {
                _Animator.runtimeAnimatorController = null;
                Editor.AnimancerEditorUtilities.SetIsInspectorExpanded(_Animator, false);

                // 折叠Animator属性,因为自定义检查器使用它来控制是否展开Animator的检查器
                using (var serializedObject = new UnityEditor.SerializedObject(this))
                {
                    var property = serializedObject.FindProperty("_Animator");
                    property.isExpanded = false;
                    serializedObject.ApplyModifiedProperties();
                }
            }

            AnimancerUtilities.IfMultiComponentThenChangeType(this);
        }
Esempio n. 18
0
        /// <summary>[Editor-Only]
        /// If a <see cref="Source"/> and <see cref="FunctionName"/> have been assigned but the
        /// <see cref="AnimancerState.Clip"/> has no event with that name, this method logs a warning.
        /// </summary>
        private void ValidateSourceHasCorrectEvent()
        {
            if (FunctionName == null || _Source == null || AnimancerUtilities.HasEvent(_Source, FunctionName))
            {
                return;
            }

            var message = ObjectPool.AcquireStringBuilder()
                          .Append("No Animation Event was found in ")
                          .Append(_Source.Clip)
                          .Append(" with the Function Name '")
                          .Append(FunctionName)
                          .Append('\'');

            if (_Source != null)
            {
                message.Append('\n');
                _Source.Root.AppendDescription(message);
            }

            Debug.LogWarning(message.ReleaseToString(), _Source.Root?.Component as Object);
        }
Esempio n. 19
0
        /************************************************************************************************************************/
        #endregion
        /************************************************************************************************************************/
        #region Initialisation
        /************************************************************************************************************************/

#if UNITY_EDITOR
        /// <summary>[Editor-Only]
        /// Called by the Unity Editor when this component is first added (in Edit Mode) and whenever the Reset command
        /// is executed from its context menu.
        /// <para></para>
        /// Destroys the playable if one has been initialised.
        /// Searches for an <see cref="UnityEngine.Animator"/> on this object, or it's children or parents.
        /// Removes the <see cref="Animator.runtimeAnimatorController"/> if it finds one.
        /// <para></para>
        /// This method also prevents you from adding multiple copies of this component to a single object. Doing so
        /// will destroy the new one immediately and change the old one's type to match the new one, allowing you to
        /// change the type without losing the values of any serialized fields they share.
        /// </summary>
        protected virtual void Reset()
        {
            OnDestroy();

            _Animator = Editor.AnimancerEditorUtilities.GetComponentInHierarchy <Animator>(gameObject);

            if (_Animator != null)
            {
                _Animator.runtimeAnimatorController = null;
                Editor.AnimancerEditorUtilities.SetIsInspectorExpanded(_Animator, false);

                // Collapse the Animator property because the custom Inspector uses that to control whether the
                // Animator's Inspector is expanded.
                using (var serializedObject = new UnityEditor.SerializedObject(this))
                {
                    var property = serializedObject.FindProperty("_Animator");
                    property.isExpanded = false;
                    serializedObject.ApplyModifiedProperties();
                }
            }

            AnimancerUtilities.IfMultiComponentThenChangeType(this);
        }
Esempio n. 20
0
        /************************************************************************************************************************/

        /// <summary>Resizes the `values` if necessary and copies the value of each property into it.</summary>
        public void GetValues(ref TValue[] values)
        {
            AnimancerUtilities.SetLength(ref values, _Values.Length);
            _Values.CopyTo(values);
        }
 /// <summary>Sets the <see cref="UpLeft"/> animation.</summary>
 /// <remarks>This is not simply a property setter because the animations will usually not need to be changed by scripts.</remarks>
 public void SetUpLeft(AnimationClip clip)
 {
     _UpLeft = clip;
     AnimancerUtilities.SetDirty(this);
 }
 /// <summary>Sets the <see cref="DownRight"/> animation.</summary>
 /// <remarks>This is not simply a property setter because the animations will usually not need to be changed by scripts.</remarks>
 public void SetDownRight(AnimationClip clip)
 {
     _DownRight = clip;
     AnimancerUtilities.SetDirty(this);
 }
Esempio n. 23
0
            /************************************************************************************************************************/
            #endregion
            /************************************************************************************************************************/
            #region Sync
            /************************************************************************************************************************/

            /// <summary>Draws a "Sync" header.</summary>
            protected void DoSyncHeaderGUI(Rect area)
            {
                using (ObjectPool.Disposable.AcquireContent(out var label, "Sync",
                                                            "Determines which child states have their normalized times constantly synchronized"))
                {
                    DoHeaderDropdownGUI(area, CurrentSpeeds, label, (menu) =>
                    {
                        var syncCount = CurrentSynchronizeChildren.arraySize;

                        var allState = syncCount == 0 ? MenuFunctionState.Selected : MenuFunctionState.Normal;
                        AddPropertyModifierFunction(menu, "All", allState,
                                                    (_) => CurrentSynchronizeChildren.arraySize = 0);

                        var syncNone = syncCount == CurrentAnimations.arraySize;
                        if (syncNone)
                        {
                            for (int i = 0; i < syncCount; i++)
                            {
                                if (CurrentSynchronizeChildren.GetArrayElementAtIndex(i).boolValue)
                                {
                                    syncNone = false;
                                    break;
                                }
                            }
                        }
                        var noneState = syncNone ? MenuFunctionState.Selected : MenuFunctionState.Normal;
                        AddPropertyModifierFunction(menu, "None", noneState, (_) =>
                        {
                            var count = CurrentSynchronizeChildren.arraySize = CurrentAnimations.arraySize;
                            for (int i = 0; i < count; i++)
                            {
                                CurrentSynchronizeChildren.GetArrayElementAtIndex(i).boolValue = false;
                            }
                        });

                        AddPropertyModifierFunction(menu, "Invert", MenuFunctionState.Normal, (_) =>
                        {
                            var count = CurrentSynchronizeChildren.arraySize;
                            for (int i = 0; i < count; i++)
                            {
                                var property       = CurrentSynchronizeChildren.GetArrayElementAtIndex(i);
                                property.boolValue = !property.boolValue;
                            }

                            var newCount = CurrentSynchronizeChildren.arraySize = CurrentAnimations.arraySize;
                            for (int i = count; i < newCount; i++)
                            {
                                CurrentSynchronizeChildren.GetArrayElementAtIndex(i).boolValue = false;
                            }
                        });

                        AddPropertyModifierFunction(menu, "Non-Stationary", MenuFunctionState.Normal, (_) =>
                        {
                            var count = CurrentAnimations.arraySize;

                            for (int i = 0; i < count; i++)
                            {
                                var state = CurrentAnimations.GetArrayElementAtIndex(i).objectReferenceValue;
                                if (state == null)
                                {
                                    continue;
                                }

                                if (i >= syncCount)
                                {
                                    CurrentSynchronizeChildren.arraySize = i + 1;
                                    for (int j = syncCount; j < i; j++)
                                    {
                                        CurrentSynchronizeChildren.GetArrayElementAtIndex(j).boolValue = true;
                                    }
                                    syncCount = i + 1;
                                }

                                CurrentSynchronizeChildren.GetArrayElementAtIndex(i).boolValue =
                                    AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) &&
                                    velocity != default;
                            }

                            TryCollapseSync();
                        });
                    });
                }
            }
Esempio n. 24
0
        /************************************************************************************************************************/

        /// <summary>
        /// Destroys the <see cref="_Playable"/> and restores the graph connection it was intercepting.
        /// </summary>
        /// <remarks>
        /// This method is NOT called automatically, so if you need to guarantee that things will get cleaned up you
        /// should use <see cref="AnimancerPlayable.Disposables"/>.
        /// </remarks>
        public virtual void Destroy()
        {
            AnimancerUtilities.RemovePlayable(_Playable);
        }