private BlendTree(AssetLayout layout, AssetInfo assetInfo, AnimatorController controller, StateConstant state, int nodeIndex) : base(layout) { AssetInfo = assetInfo; ObjectHideFlags = HideFlags.HideInHierarchy; VirtualSerializedFile virtualFile = (VirtualSerializedFile)assetInfo.File; BlendTreeNodeConstant node = state.GetBlendTree().NodeArray[nodeIndex].Instance; Name = nameof(BlendTree); Childs = new ChildMotion[node.ChildIndices.Length]; for (int i = 0; i < node.ChildIndices.Length; i++) { Childs[i] = new ChildMotion(virtualFile, controller, state, nodeIndex, i); } BlendParameter = node.BlendEventID == uint.MaxValue ? string.Empty : controller.TOS[node.BlendEventID]; BlendParameterY = node.BlendEventYID == uint.MaxValue ? string.Empty : controller.TOS[node.BlendEventYID]; MinThreshold = node.GetMinThreshold(controller.File.Version); MaxThreshold = node.GetMaxThreshold(controller.File.Version); UseAutomaticThresholds = false; NormalizedBlendValues = node.BlendDirectData.Instance.NormalizedBlendValues; BlendType = node.BlendType; }
void ReplaceAnimationClips(BlendTree blendtree) { if ((blendtree == null) || (blendtree.children.Length == 0)) { return; } if (blendtree.children[0].motion is AnimationClip) { int length = blendtree.children.Length; ChildMotion[] newChildren = new ChildMotion[length]; for (int i = 0; i < length; i++) { newChildren[i] = blendtree.children[i]; newChildren[i].motion = GetCorrespondingClip((AnimationClip)blendtree.children[i].motion); } blendtree.children = newChildren; } else { foreach (ChildMotion child in blendtree.children) { ReplaceAnimationClips(child.motion as BlendTree); } } }
protected AnimatorState CreateLandingState(AnimatorController controller, AnimatorStateMachine stateMachine) { AnimatorState landingState = stateMachine.AddState("Landing", new Vector3(450, 100, 0)); BlendTree landingBlendTree = new BlendTree(); landingBlendTree.name = "Landing"; landingBlendTree.useAutomaticThresholds = false; landingBlendTree.blendParameter = "LandDamageAmount"; ChildMotion[] childMotions = new ChildMotion[2]; childMotions[0].motion = landingClip; childMotions[0].timeScale = 1f; childMotions[0].threshold = 0f; childMotions[1].motion = landingDamageClip; childMotions[1].timeScale = 1f; childMotions[1].threshold = 1f; landingBlendTree.children = childMotions; AssetDatabase.AddObjectToAsset(landingBlendTree, controller); landingBlendTree.hideFlags = HideFlags.HideInHierarchy; landingState.motion = landingBlendTree; return(landingState); }
private void ValidateLayerBlendTree(int index, AnimatorControllerLayer layer, AnimatorController controller) { string blendTreeName = string.Format(BlendTreeName, index); if (layer.stateMachine.states.All(s => s.state.name != blendTreeName)) { Debug.Log($"Layer missing blend tree. {blendTreeName}"); DeleteObjectFromController(controller, blendTreeName); AddBlendTree(index, layer, controller); } else { Debug.Log($"Layer Blend Tree Validated {blendTreeName}."); BlendTree blendTree = layer.stateMachine.states.FirstOrDefault(s => s.state.name == blendTreeName).state.motion as BlendTree; // Just re-assign since ChildMotions aren't their own ScriptableObjects. ChildMotion childMotion0 = new ChildMotion { motion = _clips0[index], timeScale = 1 }; ChildMotion childMotion1 = new ChildMotion { motion = _clips100[index], timeScale = 1 }; blendTree.children = new ChildMotion[2] { childMotion0, childMotion1 }; AssetDatabase.SaveAssets();; } }
public static ChildMotion DeepClone(this ChildMotion child) { ChildMotion output = new ChildMotion { cycleOffset = child.cycleOffset, directBlendParameter = child.directBlendParameter, mirror = child.mirror, position = child.position, threshold = child.threshold, timeScale = child.timeScale, motion = (child.motion != null && child.motion.GetType() == typeof(BlendTree)) ? ((BlendTree)child.motion).DeepClone() : child.motion }; return(output); }
public static BlendTree DeepClone(this BlendTree tree) { BlendTree output = new BlendTree(); EditorUtility.CopySerialized(tree, output); ChildMotion[] children = new ChildMotion[tree.children.Length]; for (int i = 0; i < children.Length; i++) { children[i] = tree.children[i].DeepClone(); } output.children = children; return(output); }
public ChildMotionJson(ChildMotion childMotion, Urho3DEngine engine, PrefabContext prefabContext) { this.cycleOffset = childMotion.cycleOffset; var motion = childMotion.motion; if (motion is AnimationClip animationClip) { this.animationClip = engine.EvaluateAnimationName(animationClip, prefabContext); engine.ScheduleAssetExport(animationClip, prefabContext); } else if (motion is BlendTree blendTree) { this.hasBlendTree = true; this.blendTree = new BlendTreeJson(blendTree, engine, prefabContext); } }
private static void ApplyBlendTreeChanges(BlendTree tree, AnimationClipSwap[] treeMotions) { var newChildren = new ChildMotion[tree.children.Length]; for (int i = 0; i < tree.children.Length; i++) { ChildMotion child = tree.children[i]; if (child.motion is BlendTree childTree) { ApplyBlendTreeChanges(childTree, treeMotions[i].TreeMotions); } else { child.motion = treeMotions[i].Motion; } newChildren[i] = child; } tree.children = newChildren; }
protected AnimatorState CreateGroundedState(AnimatorController controller, AnimatorStateMachine stateMachine) { // Grounded AnimatorState groundedState = stateMachine.AddState("Grounded", new Vector3(300, 0, 0)); BlendTree groundedMotionBlendTree = new BlendTree(); groundedMotionBlendTree.name = "Movement"; groundedMotionBlendTree.useAutomaticThresholds = false; groundedMotionBlendTree.blendParameter = "Forward"; ChildMotion[] childMotions = new ChildMotion[4]; childMotions[0].motion = walkBackwardClip; childMotions[0].timeScale = reverseWalkBackAnimation ? -1 : 1; childMotions[0].threshold = -0.5f; childMotions[1].motion = idleClip; childMotions[1].timeScale = 1; childMotions[1].threshold = 0f; childMotions[2].motion = walkForwardClip; childMotions[2].timeScale = 1; childMotions[2].threshold = 0.5f; childMotions[3].motion = runClip; childMotions[3].timeScale = 1; childMotions[3].threshold = 1f; groundedMotionBlendTree.children = childMotions; AssetDatabase.AddObjectToAsset(groundedMotionBlendTree, controller); groundedMotionBlendTree.hideFlags = HideFlags.HideInHierarchy; groundedState.motion = groundedMotionBlendTree; return(groundedState); }
void TraverseClips(BlendTree output) { if ((output == null) || (output.children.Length < 1)) { return; } ChildMotion[] dstChildren = output.children; AnimationClip clip; // Let user know of empty blend trees.. if (dstChildren.Length < 1) { AddResult(string.Format("BlendTree \"{0}\" is empty.", output.name), MessageType.Error); } for (int i = 0; i < dstChildren.Length; i++) { ChildMotion child = dstChildren[i]; if (child.motion is AnimationClip) { clip = TryGetReplacementClip(child.motion as AnimationClip, output); child.motion = clip; dstChildren[i] = child; // because struct, } else { // blend tree has seeds TraverseClips(child.motion as BlendTree); } } output.children = dstChildren; }
private void AddBlendTree(int index, AnimatorControllerLayer layer, AnimatorController controller) { string controllerPath = AssetDatabase.GetAssetPath(controller); string blendTreeName = string.Format(BlendTreeName, index); AnimatorState state = layer.stateMachine.AddState(blendTreeName); state.speed = 1; BlendTree blendTree = new BlendTree { name = blendTreeName, blendType = BlendTreeType.Simple1D, blendParameter = AvaCryptKeyNames[index], }; ChildMotion childMotion0 = new ChildMotion { motion = _clips0[index], timeScale = 1 }; ChildMotion childMotion1 = new ChildMotion { motion = _clips100[index], timeScale = 1 }; blendTree.children = new ChildMotion[2] { childMotion0, childMotion1 }; state.motion = blendTree; AssetDatabase.AddObjectToAsset(blendTree, controllerPath); AssetDatabase.SaveAssets(); }
/* * [MenuItem("Assets/Export Mecanim Animation Controller", false, 301)] * private static void CreateAnimatorFile() { * var animatorController = Selection.activeObject as AnimatorController; * if (animatorController == null) { * return; * } * * CreateAsset(animatorController); * } * * [MenuItem("Assets/Export Mecanim Animation Controller", true)] * private static bool CreateAnimatorController() { * return Selection.activeObject is AnimatorController; * } */ // public static AnimatorGraphAsset Fetch(string name) { // AnimatorGraphAsset output = null; //#if UNITY_EDITOR // string pathToAnimationResource = "Assets/Resources/DB/Animator/"; // string animationFilePath = pathToAnimationResource + name + ".asset"; // output = UnityEditor.AssetDatabase.LoadAssetAtPath(animationFilePath, typeof(AnimatorGraphAsset)) as AnimatorGraphAsset; // if (output == null) { // output = CreateInstance<AnimatorGraphAsset>(); // animationFilePath = UnityEditor.AssetDatabase.GenerateUniqueAssetPath(animationFilePath); // UnityEditor.AssetDatabase.CreateAsset(output, animationFilePath); // UnityEditor.AssetDatabase.SaveAssets(); // UnityEditor.AssetDatabase.Refresh(); // } //#endif // if (output != null) { // if (output.Settings == null) // output.Settings = new AnimatorGraph(); // } // return output; // } public static void CreateAsset(AnimatorGraphAsset dataAsset, AnimatorController controller) { if (!controller) { return; } if (!dataAsset) { return; } QuantumRunner.Init();//make sure we can get debug calls from Quantum dataAsset.controller = controller; int weightTableResolution = (int)dataAsset.weight_table_resolution; int variableCount = controller.parameters.Length; dataAsset.Settings.variables = new AnimatorVariable[variableCount]; //Mecanim Parameters/Variables //make a dictionary of paramets by name for use when extracting conditions for transitions Dictionary <string, AnimatorControllerParameter> parameterDic = new Dictionary <string, AnimatorControllerParameter>(); for (int v = 0; v < variableCount; v++) { AnimatorControllerParameter parameter = controller.parameters[v]; parameterDic.Add(parameter.name, parameter); AnimatorVariable newVariable = new AnimatorVariable(); newVariable.name = parameter.name; newVariable.index = v; switch (parameter.type) { case AnimatorControllerParameterType.Bool: newVariable.type = AnimatorVariable.VariableType.Bool; newVariable.defaultBool = parameter.defaultBool; break; case AnimatorControllerParameterType.Float: newVariable.type = AnimatorVariable.VariableType.FP; newVariable.defaultFp = FP.FromFloat_UNSAFE(parameter.defaultFloat); break; case AnimatorControllerParameterType.Int: newVariable.type = AnimatorVariable.VariableType.Int; newVariable.defaultInt = parameter.defaultInt; break; case AnimatorControllerParameterType.Trigger: newVariable.type = AnimatorVariable.VariableType.Trigger; break; } dataAsset.Settings.variables[v] = newVariable; } //Mecanim State Graph int layerCount = controller.layers.Length; dataAsset.clips.Clear(); dataAsset.Settings.layers = new AnimatorLayer[layerCount]; for (int l = 0; l < layerCount; l++) { AnimatorLayer newLayer = new AnimatorLayer(); newLayer.name = controller.layers[l].name; newLayer.id = l; int stateCount = controller.layers[l].stateMachine.states.Length; newLayer.states = new Quantum.AnimatorState[stateCount + 1];//additional element for the any state Dictionary <UnityEditor.Animations.AnimatorState, Quantum.AnimatorState> stateDictionary = new Dictionary <AnimatorState, Quantum.AnimatorState>(); for (int s = 0; s < stateCount; s++) { UnityEditor.Animations.AnimatorState state = controller.layers[l].stateMachine.states[s].state; Quantum.AnimatorState newState = new Quantum.AnimatorState(); newState.name = state.name; newState.id = state.nameHash; newState.isDefault = controller.layers[l].stateMachine.defaultState == state; newState.speed = FP.FromFloat_UNSAFE(state.speed); newState.cycleOffset = FP.FromFloat_UNSAFE(state.cycleOffset); if (state.motion != null) { AnimationClip clip = state.motion as AnimationClip; if (clip != null) { dataAsset.clips.Add(clip); AnimatorClip newClip = new AnimatorClip(); newClip.name = state.motion.name; newClip.data = Extract(clip); newState.motion = newClip; } else { BlendTree tree = state.motion as BlendTree; if (tree != null) { int childCount = tree.children.Length; AnimatorBlendTree newBlendTree = new AnimatorBlendTree(); newBlendTree.name = state.motion.name; newBlendTree.motionCount = childCount; newBlendTree.motions = new AnimatorMotion[childCount]; newBlendTree.positions = new FPVector2[childCount]; newBlendTree.weights = new FP[childCount]; string parameterXname = tree.blendParameter; string parameterYname = tree.blendParameterY; for (int v = 0; v < variableCount; v++) { if (controller.parameters[v].name == parameterXname) { newBlendTree.blendParameterIndex = v; } if (controller.parameters[v].name == parameterYname) { newBlendTree.blendParameterIndexY = v; } } for (int c = 0; c < childCount; c++) { ChildMotion cMotion = tree.children[c]; AnimationClip cClip = cMotion.motion as AnimationClip; newBlendTree.positions[c] = new FPVector2(FP.FromFloat_UNSAFE(cMotion.position.x), FP.FromFloat_UNSAFE(cMotion.position.y)); if (cClip != null) { dataAsset.clips.Add(cClip); AnimatorClip newClip = new AnimatorClip(); newClip.data = Extract(cClip); newClip.name = newClip.clipName; newBlendTree.motions[c] = newClip; } } FP val = FP._0 / 21; newBlendTree.CalculateWeightTable(weightTableResolution); newState.motion = newBlendTree; } } } newLayer.states[s] = newState; stateDictionary.Add(state, newState); } //State Transistions //once the states have all been created //we'll hook up the transitions for (int s = 0; s < stateCount; s++) { UnityEditor.Animations.AnimatorState state = controller.layers[l].stateMachine.states[s].state; Quantum.AnimatorState newState = newLayer.states[s]; int transitionCount = state.transitions.Length; newState.transitions = new Quantum.AnimatorTransition[transitionCount]; for (int t = 0; t < transitionCount; t++) { AnimatorStateTransition transition = state.transitions[t]; if (!stateDictionary.ContainsKey(transition.destinationState)) { continue; } Quantum.AnimatorTransition newTransition = new Quantum.AnimatorTransition(); newTransition.index = t; newTransition.name = string.Format("{0} to {1}", state.name, transition.destinationState.name); newTransition.duration = FP.FromFloat_UNSAFE(transition.duration * state.motion.averageDuration); newTransition.hasExitTime = transition.hasExitTime; newTransition.exitTime = FP.FromFloat_UNSAFE(transition.exitTime * state.motion.averageDuration); newTransition.offset = FP.FromFloat_UNSAFE(transition.offset * transition.destinationState.motion.averageDuration); newTransition.destinationStateId = stateDictionary[transition.destinationState].id; newTransition.destinationStateName = stateDictionary[transition.destinationState].name; newTransition.canTransitionToSelf = transition.canTransitionToSelf; int conditionCount = transition.conditions.Length; newTransition.conditions = new Quantum.AnimatorCondition[conditionCount]; for (int c = 0; c < conditionCount; c++) { UnityEditor.Animations.AnimatorCondition condition = state.transitions[t].conditions[c]; if (!parameterDic.ContainsKey(condition.parameter)) { continue; } AnimatorControllerParameter parameter = parameterDic[condition.parameter]; Quantum.AnimatorCondition newCondition = new Quantum.AnimatorCondition(); newCondition.variableName = condition.parameter; newCondition.mode = (Quantum.AnimatorCondition.Modes)condition.mode; switch (parameter.type) { case AnimatorControllerParameterType.Float: newCondition.thresholdFp = FP.FromFloat_UNSAFE(condition.threshold); break; case AnimatorControllerParameterType.Int: newCondition.thresholdInt = Mathf.RoundToInt(condition.threshold); break; } newTransition.conditions[c] = newCondition; } newState.transitions[t] = newTransition; } } //Create Any State Quantum.AnimatorState anyState = new Quantum.AnimatorState(); anyState.name = "Any State"; anyState.id = anyState.name.GetHashCode(); anyState.isAny = true;//important for this one AnimatorStateTransition[] anyStateTransitions = controller.layers[l].stateMachine.anyStateTransitions; int anyStateTransitionCount = anyStateTransitions.Length; anyState.transitions = new Quantum.AnimatorTransition[anyStateTransitionCount]; for (int t = 0; t < anyStateTransitionCount; t++) { AnimatorStateTransition transition = anyStateTransitions[t]; if (!stateDictionary.ContainsKey(transition.destinationState)) { continue; } Quantum.AnimatorTransition newTransition = new Quantum.AnimatorTransition(); newTransition.index = t; newTransition.name = string.Format("Any State to {0}", transition.destinationState.name); newTransition.duration = FP.FromFloat_UNSAFE(transition.duration); newTransition.hasExitTime = transition.hasExitTime; newTransition.exitTime = FP._1; newTransition.offset = FP.FromFloat_UNSAFE(transition.offset * transition.destinationState.motion.averageDuration); newTransition.destinationStateId = stateDictionary[transition.destinationState].id; newTransition.destinationStateName = stateDictionary[transition.destinationState].name; newTransition.canTransitionToSelf = transition.canTransitionToSelf; int conditionCount = transition.conditions.Length; newTransition.conditions = new Quantum.AnimatorCondition[conditionCount]; for (int c = 0; c < conditionCount; c++) { UnityEditor.Animations.AnimatorCondition condition = anyStateTransitions[t].conditions[c]; if (!parameterDic.ContainsKey(condition.parameter)) { continue; } AnimatorControllerParameter parameter = parameterDic[condition.parameter]; Quantum.AnimatorCondition newCondition = new Quantum.AnimatorCondition(); newCondition.variableName = condition.parameter; newCondition.mode = (Quantum.AnimatorCondition.Modes)condition.mode; switch (parameter.type) { case AnimatorControllerParameterType.Float: newCondition.thresholdFp = FP.FromFloat_UNSAFE(condition.threshold); break; case AnimatorControllerParameterType.Int: newCondition.thresholdInt = Mathf.RoundToInt(condition.threshold); break; } newTransition.conditions[c] = newCondition; } anyState.transitions[t] = newTransition; } newLayer.states[stateCount] = anyState; dataAsset.Settings.layers[l] = newLayer; } EditorUtility.SetDirty(dataAsset); }
private static Motion RemapMotion(Dictionary <QualifiedAnimation, AnimationClip> remapping, List <QualifiedAnimation> qualifiedAnimations, Dictionary <BlendTree, BlendTree> biTreesReferences, ChildMotion copyOfChild) { switch (copyOfChild.motion) { case AnimationClip clip: return(remapping[qualifiedAnimations.First(animation => animation.Clip == clip)]); case BlendTree tree: return(biTreesReferences[tree]); default: return(copyOfChild.motion); } }
private void RecursionAnalyzeAnimatorStateMachine(AnimatorStateMachine stateMachine, string animationFlolder) { //遍历states for (int i = 0; i < stateMachine.states.Length; i++) { var animatorState = stateMachine.states[i]; var motion = animatorState.state.motion; if (motion != null) { if (motion is BlendTree) { BlendTree bt = motion as BlendTree; ChildMotion[] childMotions = new ChildMotion[bt.children.Length]; for (int j = 0; j < bt.children.Length; j++) { var childMotion = bt.children[j]; var motionClip = GetAnimationClip(childMotion.motion.name, animationFlolder); if (motionClip == null) { Debug.LogError("没有找到" + motion.name + "的动画控制器"); } else { Debug.Log(string.Format("Name:{0} Motion:{1}", animatorState.state.name, childMotion.motion)); //根据名字找到对应的prefab 然后找出里面的动画文件加载 //childMotion.motion = (Motion)motionClip; //var newChildMotion = new ChildMotion() { motion = motionClip, cycleOffset = childMotion.cycleOffset, mirror = childMotion.mirror, directBlendParameter = childMotion.directBlendParameter, position = childMotion.position, threshold = childMotion.threshold, timeScale = childMotion.timeScale }; //childMotion = newChildMotion; childMotions[j] = new ChildMotion() { motion = (Motion)motionClip, cycleOffset = childMotion.cycleOffset, mirror = childMotion.mirror, directBlendParameter = childMotion.directBlendParameter, position = childMotion.position, threshold = childMotion.threshold, timeScale = childMotion.timeScale }; } } //bt.children = childMotions; BlendTree newBt = new BlendTree() { blendParameter = bt.blendParameter, blendParameterY = bt.blendParameterY, blendType = bt.blendType, hideFlags = bt.hideFlags, maxThreshold = bt.maxThreshold, minThreshold = bt.minThreshold, name = bt.name, useAutomaticThresholds = bt.useAutomaticThresholds, children = childMotions, }; animatorState.state.motion = newBt; } else { animatorState.state.motion = null; var motionClip = GetAnimationClip(motion.name, animationFlolder); if (motionClip == null) { Debug.LogError("没有找到" + motion.name + "的动画控制器"); } else { animatorState.state.motion = (Motion)motionClip; Debug.Log(string.Format("Name:{0} Motion:{1}", animatorState.state.name, motion)); } } } } //遍历substatemachine for (int j = 0; j < stateMachine.stateMachines.Length; j++) { var stateMachines = stateMachine.stateMachines[j]; RecursionAnalyzeAnimatorStateMachine(stateMachines.stateMachine, animationFlolder); } }