예제 #1
0
 /// <summary>
 /// Play a state, using an instant transition. The state will immediately be the current played state.
 /// </summary>
 /// <param name="state">state index to play</param>
 /// <param name="layer">Layer the state should be played on</param>
 public void SnapTo(int state, int layer = 0)
 {
     AssertLayerInBounds(layer, state, "Snap to state");
     Play(state, TransitionData.Instant(), layer);
 }
예제 #2
0
 public AnimationPlayerState Play(int state, TransitionData transition, string transitionName)
 {
     return(Play(state, transition, transitionName, true));
 }
예제 #3
0
        public void InitializeSelf(PlayableGraph graph, TransitionData defaultTransition, List <ClipSwapCollection> clipSwapCollections,
                                   Dictionary <string, float> blendVariableValues)
        {
            this.defaultTransition   = defaultTransition;
            this.clipSwapCollections = clipSwapCollections;
            playInstructionQueue     = new PlayAtTimeInstructionQueue(this);

            containingGraph = graph;
            if (states.Count == 0)
            {
                stateMixer = AnimationMixerPlayable.Create(graph, 0, false);
                return;
            }

            foreach (var transition in transitions)
            {
                transition.FetchStates(states);
            }

            runtimePlayables = new Playable[states.Count];

            stateMixer = AnimationMixerPlayable.Create(graph, states.Count, false);
            stateMixer.SetInputWeight(0, 1f);
            currentPlayedState = 0;

            for (int i = 0; i < states.Count; i++)
            {
                var state = states[i];
                if (state.animationEvents.Count > 0)
                {
                    anyStatesHasAnimationEvents = true;
                }

                stateNameToIdx[state.Name] = i;

                var playable = state.Initialize(graph, varTo1DBlendControllers, varTo2DBlendControllers, all2DControllers, clipSwapCollections);
                runtimePlayables[i] = playable;
                graph.Connect(playable, 0, stateMixer, i);

                state.RegisterUsedBlendVarsIn(blendVariableValues);
            }

            activeWhenBlendStarted = new List <bool>(states.Count);
            valueWhenBlendStarted  = new List <float>(states.Count);
            timeLastFrame          = new List <double>();
            for (int i = 0; i < states.Count; i++)
            {
                activeWhenBlendStarted.Add(false);
                valueWhenBlendStarted.Add(0f);
                timeLastFrame.Add(0f);
            }

            transitionLookup = new int[states.Count, states.Count];
            for (int i = 0; i < states.Count; i++)
            {
                for (int j = 0; j < states.Count; j++)
                {
                    transitionLookup[i, j] = -1;
                }
            }

            for (var i = 0; i < transitions.Count; i++)
            {
                var transition = transitions[i];
                if (!transition.isDefault)
                {
                    continue;
                }

                var fromState = states.IndexOf(transition.FromState);
                var toState   = states.IndexOf(transition.ToState);
                if (fromState == -1 || toState == -1)
                {
                    //TODO: fixme
                }
                else
                {
                    if (transitionLookup[fromState, toState] != -1)
                    {
                        Debug.LogWarning($"Found two default transitions from {states[fromState]} to {states[toState]}");
                    }

                    transitionLookup[fromState, toState] = i;
                }
            }
        }
        private void HandleInitialization(bool isGUICall)
        {
            if (scriptReloadChecker == null)
            {
                // Unity persists some objects through reload, and fails to persist others. This makes it hard to figure out if
                // something needs to be re-cached. This solves that - we know that Unity can't persist a raw object, so if it's null, a reload is neccessary.
                scriptReloadChecker = new object();

                metaDataDrawer         = new MetaDataDrawer(animationPlayer);
                stylesCreated          = false;
                transitionsNeedsUpdate = true;
                MarkDirty();
            }

            if (isGUICall && !stylesCreated)
            {
                var backgroundTex = EditorUtilities.MakeTex(1, 1, new Color(1.0f, 1.0f, 1.0f, .1f));
                editLayerStyle = new GUIStyle {
                    normal = { background = backgroundTex }
                };

                var buttonBackgroundTex   = EditorUtilities.MakeTex(1, 1, new Color(1.0f, 1.0f, 1.0f, 0.05f));
                var buttonSelectedTex     = EditorUtilities.MakeTex(1, 1, new Color(1.0f, 1.0f, 1.0f, 0.05f));
                var buttonNotSelectedText = EditorUtilities.MakeTex(1, 1, new Color(1.0f, 1.0f, 1.0f, 0.2f));

                editLayerButton_Background = new GUIStyle {
                    normal = { background = buttonBackgroundTex }
                };

                editLayerButton_NotSelected = new GUIStyle(GUI.skin.label)
                {
                    normal    = { background = buttonNotSelectedText },
                    alignment = TextAnchor.MiddleCenter
                };

                editLayerButton_Selected = new GUIStyle(GUI.skin.label)
                {
                    normal    = { background = buttonSelectedTex },
                    alignment = TextAnchor.MiddleCenter
                };

                stylesCreated = true;
            }

            if (animationPlayer.layers == null || animationPlayer.layers.Length == 0)
            {
                animationPlayer.layers    = new AnimationLayer[1];
                animationPlayer.layers[0] = AnimationLayer.CreateLayer();

                if (animationPlayer.defaultTransition == default(TransitionData))
                {
                    animationPlayer.defaultTransition = TransitionData.Linear(.1f); //default shouldn't be snap
                }
                return;
            }

            if (stateNamesNeedsUpdate)
            {
                stateNamesNeedsUpdate = false;
                allStateNames         = new string[animationPlayer.layers.Length][];
                for (int i = 0; i < animationPlayer.layers.Length; i++)
                {
                    var states = animationPlayer.layers[i].states;
                    allStateNames[i] = new string[states.Count];
                    for (int j = 0; j < states.Count; j++)
                    {
                        allStateNames[i][j] = states[j].Name;
                    }
                }
            }

            if (transitionsNeedsUpdate)
            {
                transitionsNeedsUpdate = false;
                foreach (var layer in animationPlayer.layers)
                {
                    foreach (var transition in layer.transitions)
                    {
                        transition.FetchStates(layer.states);
                    }
                }
            }

            if (previewer == null)
            {
                previewer = new AnimationStatePreviewer(animationPlayer);
            }
        }
예제 #5
0
        private AnimationPlayerState Play(int newState, TransitionData transitionData, string transitionName, bool clearQueuedPlayInstructions)
        {
            if (newState < 0 || newState >= states.Count)
            {
                Debug.LogError($"Trying to play out of bounds clip {newState}! There are {states.Count} clips in the animation player");
                return(null);
            }

            if (transitionData.type == TransitionType.Curve && transitionData.curve == null)
            {
                Debug.LogError("Trying to play an animationCurve based transition, but the transition curve is null!");
                return(null);
            }

            foreach (var animationEvent in states[currentPlayedState].animationEvents)
            {
                animationEvent.ClearRegisteredForCurrentState();
            }

            if (clearQueuedPlayInstructions)
            {
                playInstructionQueue.Clear();
            }

            numberOfStateChanges++;

            if (transitionData.duration <= 0f)
            {
                DoInstantTransition();
            }
            else if (transitionData.type == TransitionType.Clip)
            {
                StartClipTransition();
            }
            else
            {
                StartTimedTransition();
            }

            states[newState].OnWillStartPlaying(ref runtimePlayables[newState]);

            return(states[newState]);

            // HELPERS:

            void DoInstantTransition()
            {
                for (int i = 0; i < stateMixer.GetInputCount(); i++)
                {
                    stateMixer.SetInputWeight(i, 0);
                }

                stateMixer.SetInputWeight(newState, 1);
                runtimePlayables[newState].SetTime(0);
                currentPlayedState = newState;
                transitioning      = false;

                ClearFinishedTransitionStates();
            }

            void StartClipTransition()
            {
                var transitionState = AnimationClipPlayable.Create(containingGraph, transitionData.clip);

                var transitionStateindex = stateMixer.GetInputCount();

                stateMixer.SetInputCount(transitionStateindex + 1);

                containingGraph.Connect(transitionState, 0, stateMixer, transitionStateindex);

                for (int i = 0; i < transitionStateindex; i++)
                {
                    stateMixer.SetInputWeight(i, 0);
                }
                stateMixer.SetInputWeight(transitionStateindex, 1);

                transitionState.SetTime(0); // Fix for a bug where this is set to some other value on startup (for example 0.333 in one test?)

                transitioning         = true;
                transitionStartTime   = Time.time;
                currentTransitionData = transitionData;
                currentTransitionName = transitionName;
                currentPlayedState    = newState;

                activeWhenBlendStarted.Add(true);
                valueWhenBlendStarted.Add(1);
            }

            void StartTimedTransition()
            {
                var currentWeightOfState = stateMixer.GetInputWeight(newState);
                var isCurrentlyPlaying   = currentWeightOfState > 0f;

                if (!isCurrentlyPlaying)
                {
                    runtimePlayables[newState].SetTime(0f);
                    //This makes animation events set to time 0 play, by simulating that the frame jumped forwards a second.
                    timeLastFrame[newState] = -1f;
                }
                else if (!states[newState].Loops)
                {
                    if (transitionData.duration <= 0f)
                    {
                        runtimePlayables[newState].SetTime(0);
                    }
                    else
                    {
                        // We need to blend to a state currently playing, but since it's not looping, blending to a time different than 0 would look bad.
                        // So we do this:
                        // Move the old version of the state to a new spot in the mixer, copy over the time and weight to that new spot.
                        // Create a new version of the state at the old spot
                        // Blend to the new state
                        // Later, when the copy's weight hits zero, we discard it.

                        var original  = runtimePlayables[newState];
                        var copy      = states[newState].GeneratePlayable(containingGraph, varTo1DBlendControllers, varTo2DBlendControllers, all2DControllers);
                        var copyIndex = stateMixer.GetInputCount();
                        stateMixer.SetInputCount(copyIndex + 1);

                        containingGraph.Connect(copy, 0, stateMixer, copyIndex);

                        activeWhenBlendStarted.Add(true);
                        valueWhenBlendStarted.Add(currentWeightOfState);

                        copy.SetTime(original.GetTime());

                        runtimePlayables[newState].SetTime(0);
                        stateMixer.SetInputWeight(copyIndex, currentWeightOfState);
                        stateMixer.SetInputWeight(newState, 0);
                    }
                }

                for (int i = 0; i < stateMixer.GetInputCount(); i++)
                {
                    var currentMixVal = stateMixer.GetInputWeight(i);
                    activeWhenBlendStarted[i] = currentMixVal > 0f;
                    valueWhenBlendStarted[i]  = currentMixVal;
                }

                transitioning         = true;
                currentPlayedState    = newState;
                currentTransitionData = transitionData;
                transitionStartTime   = Time.time;
            }
        }
예제 #6
0
 public PlayAtTimeInstruction(float playAtTime, int stateToPlay, TransitionData transition)
 {
     this.playAtTime  = playAtTime;
     this.stateToPlay = stateToPlay;
     this.transition  = transition;
 }
예제 #7
0
 public void PlayAfterSeconds(float seconds, int state, TransitionData transition)
 {
     playInstructionQueue.Enqueue(new PlayAtTimeInstruction(Time.time + seconds, state, transition));
 }
예제 #8
0
        private void Play(int newState, TransitionData transitionData, bool clearQueuedPlayInstructions = true)
        {
            if (clearQueuedPlayInstructions)
            {
                playInstructionQueue.Clear();
            }

            if (newState < 0 || newState >= states.Count)
            {
                Debug.LogError($"Trying to play out of bounds clip {newState}! There are {states.Count} clips in the animation player");
                return;
            }

            if (transitionData.type == TransitionType.Curve && transitionData.curve == null)
            {
                Debug.LogError("Trying to play an animationCurve based transition, but the transition curve is null!");
                return;
            }

            var currentWeightOfState = stateMixer.GetInputWeight(newState);
            var isCurrentlyPlaying   = currentWeightOfState > 0f;

            if (isCurrentlyPlaying)
            {
                if (!states[newState].Loops)
                {
                    // We need to blend to a state currently playing, but want to blend to it at time 0, as it's not looping.
                    // So we do this:
                    // Move the old version of the state to a new spot in the mixer, copy over the time and weight
                    // Create a new version of the state at the old spot
                    // Blend to the new state

                    var original  = runtimePlayables[newState];
                    var copy      = states[newState].GeneratePlayable(containingGraph, varTo1DBlendControllers, varTo2DBlendControllers, blendVars);
                    var copyIndex = stateMixer.GetInputCount();
                    stateMixer.SetInputCount(copyIndex + 1);

                    containingGraph.Connect(copy, 0, stateMixer, copyIndex);

                    activeWhenBlendStarted.Add(true);
                    valueWhenBlendStarted.Add(currentWeightOfState);

                    copy.SetTime(original.GetTime());
                    original.SetTime(0);

                    stateMixer.SetInputWeight(copyIndex, currentWeightOfState);
                    stateMixer.SetInputWeight(newState, 0);
                }
            }
            else
            {
                runtimePlayables[newState].SetTime(0f);
            }
            timeOfPlayedStateLastFrame = runtimePlayables[newState].GetTime();

            if (transitionData.duration <= 0f)
            {
                for (int i = 0; i < stateMixer.GetInputCount(); i++)
                {
                    stateMixer.SetInputWeight(i, i == newState ? 1f : 0f);
                }

                currentPlayedState = newState;
                transitioning      = false;
            }
            else
            {
                for (int i = 0; i < stateMixer.GetInputCount(); i++)
                {
                    var currentMixVal = stateMixer.GetInputWeight(i);
                    activeWhenBlendStarted[i] = currentMixVal > 0f;
                    valueWhenBlendStarted[i]  = currentMixVal;
                }

                transitioning         = true;
                currentPlayedState    = newState;
                currentTransitionData = transitionData;
                transitionStartTime   = Time.time;
            }
        }
예제 #9
0
 public void PlayUsingExternalTransition(int state, TransitionData transitionData)
 {
     Play(state, transitionData);
 }