public int AddState(AnimationPlayerState state, Dictionary <string, float> blendVariableValues) { if (states.Count == 0) { state.RegisterUsedBlendVarsIn(blendVariableValues); HandleAddedFirstStateAfterStartup(state, blendVariableValues); return(0); } states.Add(state); if (state.animationEvents.Count > 0) { anyStatesHasAnimationEvents = true; } var playable = state.Initialize(containingGraph, varTo1DBlendControllers, varTo2DBlendControllers, all2DControllers, clipSwapCollections); var indexOfNew = states.Count - 1; stateNameToIdx[state.Name] = indexOfNew; Array.Resize(ref runtimePlayables, runtimePlayables.Length + 1); runtimePlayables[runtimePlayables.Length - 1] = playable; activeWhenBlendStarted.Add(false); valueWhenBlendStarted.Add(0f); timeLastFrame.Add(0d); var newLookup = new int[states.Count, states.Count]; for (int i = 0; i < transitionLookup.GetLength(0); i++) { for (int j = 0; j < transitionLookup.GetLength(1); j++) { newLookup[i, j] = transitionLookup[i, j]; } } for (int i = 0; i < states.Count; i++) { newLookup[i, indexOfNew] = -1; newLookup[indexOfNew, i] = -1; } transitionLookup = newLookup; stateMixer.SetInputCount(stateMixer.GetInputCount() + 1); //Shift all excess playables (ie blend helpers) one index up. Since their order doesn't count, could just swap the first one to the last index? for (int i = stateMixer.GetInputCount() - 1; i > states.Count; i--) { var p = stateMixer.GetInput(i); var weight = stateMixer.GetInputWeight(i); containingGraph.Disconnect(stateMixer, i - 1); containingGraph.Connect(p, 0, stateMixer, i); stateMixer.SetInputWeight(i, weight); } containingGraph.Connect(playable, 0, stateMixer, indexOfNew); return(indexOfNew); }
private void DrawCurrentSelectedState(AnimationStateWrapper.Type type) { bool markDirty = false; StateDataDrawer.ReloadCheck(); AnimationPlayerState selectedState = null; if (type == AnimationStateWrapper.Type.BlendTree1D) { selectedState = animationStateWrapper.blendTree1D; } else if (type == AnimationStateWrapper.Type.BlendTree2D) { selectedState = animationStateWrapper.blendTree2D; } else if (type == AnimationStateWrapper.Type.PlayRandomClip) { selectedState = animationStateWrapper.playRandomClip; } else if (type == AnimationStateWrapper.Type.SingleClip) { selectedState = animationStateWrapper.singleClip; } if (selectedState != null) { StateDataDrawer.DrawStateData(selectedState, ref markDirty); } if (markDirty) { EditorUtility.SetDirty(animationStateWrapper); } }
private static void DrawTransitionSelection(AnimationLayer layer, AnimationPlayerState selectedState, string fromStateName, StateTransition selectedTransition, Action <StateTransition> SetSelectedTransition) { transitionsFromState.Clear(); foreach (var transition in layer.transitions) { if (transition.FromState == selectedState) { transitionsFromState.Add(transition); } } transitionsFromState.Sort((t1, t2) => t1.ToState.Name.CompareTo(t2.ToState.Name)); //@TODO: Grab hold of NaturalComparrison from Mesmer, use it, so state_2 doesn't sort under state_11 if (transitionsFromState.Count == 0) { EditorGUILayout.LabelField($"No defined transitions from {fromStateName}"); } else { EditorGUILayout.LabelField($"Transitions from {fromStateName}:"); var buttonWidth = 100f; foreach (var transition in transitionsFromState) { var width = GUI.skin.button.CalcSize(new GUIContent(transition.name)).x + 20f; buttonWidth = Mathf.Max(width, buttonWidth); } EditorGUILayout.Space(); AnimationPlayerState lastToState = null; EditorUtilities.DrawIndented(() => { for (var i = 0; i < transitionsFromState.Count; i++) { var transition = transitionsFromState[i]; if (transition.ToState != lastToState) { lastToState = transition.ToState; EditorGUILayout.LabelField($"Transitions to {lastToState.Name}"); } using (new GUILayout.HorizontalScope()) using (new EditorGUI.DisabledScope(transition == selectedTransition)) { if (GUILayout.Button(transition.name, GUILayout.Width(buttonWidth))) { SetSelectedTransition(transition); } if (transition.isDefault) { EditorGUILayout.LabelField("(Default)"); } } } }); } }
/// <summary> /// Adds a new state to the AnimationPlayer, and makes sure that all the graphs are correctly setup. /// At edit time, just add new states directly into the layer's states /// </summary> /// <param name="state">State to add.</param> /// <param name="layer">Layer to add the state to.</param> /// <returns>The index of the added state</returns> public int AddState(AnimationPlayerState state, int layer = 0) { if (!Application.isPlaying) { Debug.LogError("Don't call AnimationPlayer.AddState at runtime! Just add states to the layers directly!"); return(-1); } return(layers[layer].AddState(state, blendVariableValues)); }
private void AddAllClipsFromStateTo(AnimationPlayerState state, List <AnimationClip> list) { switch (state) { case BlendTree1D blendTree1D: { foreach (var clip in blendTree1D.blendTree.Select(entry => entry.clip)) { AddClip(clip); } break; } case BlendTree2D blendTree2D: { foreach (var clip in blendTree2D.blendTree.Select(entry => entry.clip)) { AddClip(clip); } break; } case PlayRandomClip playRandomClip: { foreach (var clip in playRandomClip.clips) { AddClip(clip); } break; } case Sequence sequence: { foreach (var clip in sequence.clips) { AddClip(clip); } break; } case SingleClip singleClip: { AddClip(singleClip.clip); break; } } void AddClip(AnimationClip clip) { if (clip != null && !list.Contains(clip)) { list.Add(clip); } } }
private int CompareListIndices(AnimationPlayerState x, AnimationPlayerState y) { var xIndex = Array.IndexOf(serializedStateOrder, x.GUID); var yIndex = Array.IndexOf(serializedStateOrder, y.GUID); if (xIndex < yIndex) { return(-1); } return(xIndex > yIndex ? 1 : 0); }
public (AnimationClip, float) GetCurrentActualClipAndWeight(AnimationPlayerState state, int clipIndex = 0) { var stateIndex = states.IndexOf(state); if (stateIndex == -1) { Debug.LogError($"The state {state} is not on this layer!"); return(null, -1); } return(GetCurrentActualClipAndWeight(stateIndex, clipIndex)); }
/// <summary> /// If the first state gets added after Initialize and InitializeLayerBlending has run, we disconnect and destroy the empty state mixer, and then /// re-initialize. /// </summary> private void HandleAddedFirstStateAfterStartup(AnimationPlayerState state, Dictionary <string, float> blendVariableValues) { states.Add(state); // layerMixer.IsValid => there's more than 1 layer. if (layerMixer.IsValid()) { containingGraph.Disconnect(layerMixer, layerIndex); } stateMixer.Destroy(); InitializeSelf(containingGraph, defaultTransition, clipSwapCollections, blendVariableValues); if (layerMixer.IsValid()) { InitializeLayerBlending(containingGraph, layerIndex, layerMixer); } }
public static void DrawStateData(AnimationPlayerState state, ref bool markDirty) { const float labelWidth = 55f; var old = state.Name; state.Name = EditorUtilities.TextField("Name", state.Name, labelWidth); if (old != state.Name) { markDirty = true; } state.speed = EditorUtilities.DoubleField("Speed", state.speed, labelWidth); switch (state) { case SingleClip singleClipState: DrawSingleClipState(singleClipState, ref markDirty, labelWidth); break; case BlendTree1D blendTree1D: Draw1DBlendTree(blendTree1D, ref markDirty); break; case BlendTree2D blendTree2D: Draw2DBlendTree(blendTree2D, ref markDirty); break; case PlayRandomClip playRandom: DrawSelectRandomState(playRandom, ref markDirty); break; case Sequence sequence: DrawSequence(sequence, ref markDirty); break; default: EditorGUILayout.LabelField($"Unknown animation state type: {(state == null ? "null" : state.GetType().Name)}"); break; } }
private static IEnumerable <AnimationClip> GetClips(AnimationPlayerState state) { switch (state) { case BlendTree1D blendTree1D: foreach (var clip in blendTree1D.blendTree.Select(entry => entry.clip)) { yield return(clip); } break; case BlendTree2D blendTree2D: foreach (var clip in blendTree2D.blendTree.Select(entry => entry.clip)) { yield return(clip); } break; case PlayRandomClip playRandomClip: foreach (var clip in playRandomClip.clips) { yield return(clip); } break; case Sequence sequence: foreach (var clip in sequence.clips) { yield return(clip); } break; case SingleClip singleClip: yield return(singleClip.clip); break; } }
private static void DrawCreateNewTransition(AnimationPlayer animationPlayer, Action <StateTransition> SetSelectedTransition, string[] stateNamesInLayer, string fromStateName, string toStateName, AnimationPlayerState selectedState, AnimationLayer layer) { using (new EditorGUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); if (GUILayout.Button($"Create new transition from {fromStateName}")) { GenericMenu menu = new GenericMenu(); foreach (var state in stateNamesInLayer) { menu.AddItem(new GUIContent($"Transition from {fromStateName} to {state}"), false, () => { //@TODO: If this is the first transition between the states, it should be set as default. EditorUtilities.RecordUndo(animationPlayer, $"Adding transition from {fromStateName} to {toStateName}"); var newState = new StateTransition { FromState = selectedState, ToState = layer.states.Find(s => s.Name == state), transitionData = TransitionData.Linear(.2f) }; layer.transitions.Add(newState); SetSelectedTransition(newState); }); } menu.ShowAsContext(); } } }
private static List <StateTransition> GetTransitionsBetweenStates(AnimationLayer layer, AnimationPlayerState selectedState, AnimationPlayerState selectedToState) { var allTransitionsBetweenStates = new List <StateTransition>(); foreach (var transition in layer.transitions) { if (transition.FromState == selectedState && transition.ToState == selectedToState) { allTransitionsBetweenStates.Add(transition); } } return(allTransitionsBetweenStates); }