/// <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); }
public AnimationPlayerState Play(int state, TransitionData transition, string transitionName) { return(Play(state, transition, transitionName, true)); }
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); } }
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; } }
public PlayAtTimeInstruction(float playAtTime, int stateToPlay, TransitionData transition) { this.playAtTime = playAtTime; this.stateToPlay = stateToPlay; this.transition = transition; }
public void PlayAfterSeconds(float seconds, int state, TransitionData transition) { playInstructionQueue.Enqueue(new PlayAtTimeInstruction(Time.time + seconds, state, transition)); }
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; } }
public void PlayUsingExternalTransition(int state, TransitionData transitionData) { Play(state, transitionData); }