using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using UnityEditor.Animations; using YKMoon; namespace YKMoonEditor { public partial class YKAnimatorEditorUtility { public static Vector2 stateZeroPosition = new Vector2(30, 120); // y x→ //↓ public static float stateYScale = 100; public static float stateXScale = 300; public static AnimatorController GenerateAnimatorController(YKAnimatorListener target, YKAnimatorPresetSettingStyle style) { if(target == null) { return null; } var path = GetSaveControllerPath(target); if(string.IsNullOrEmpty(path)) return null; var originPath = AssetDatabase.GetAssetPath(style.controllerPreset); AssetDatabase.CopyAsset(originPath, path); var controller = AssetDatabase.LoadAssetAtPath(path); /*var controller = AnimatorController.CreateAnimatorControllerAtPath(path); var origin = style.controllerPreset; //layers foreach(var originLayer in origin.layers) { var layer = new AnimatorControllerLayer(); var }*/ // Create controller and hook up transitions. //EditorUtility.CopySerialized(origin, controller); //var controller = AnimatorController.Instantiate(origin); //AssetDatabase.CreateAsset(controller, path); /*var originClips = origin.animationClips; Dictionary clipDict = new Dictionary(); foreach(var clip in originClips) { var newClip = Object.Instantiate(clip); newClip.name = clip.name; AssetDatabase.AddObjectToAsset(newClip, controller); clipDict.Add(clip, newClip); } foreach(var layer in controller.layers) { foreach(var stateInfo in layer.stateMachine.states) { var originMotion = stateInfo.state.motion; if(originMotion == null) { continue; } if(clipDict.ContainsKey(originMotion)) { var motion = clipDict[originMotion]; stateInfo.state.motion = motion; } } }*/ AssetDatabase.SaveAssets(); AssetDatabase.ImportAsset(path); return controller; } public static AnimatorController CreateUIController(string path) { // Create controller and hook up transitions. path = path.Replace(".asset", ".controller"); AnimatorController controller = AnimatorController.CreateAnimatorControllerAtPath(path); /*if (parentObject != null) { controller = new AnimatorController(); controller.name = parentObject.name; controller.AddLayer("Base Layer"); controller.layers[0].stateMachine.AddStateMachineBehaviour(); AssetDatabase.AddObjectToAsset(controller, parentObject); } else { string path = "Assets/temp.controller"; controller = AnimatorController.CreateAnimatorControllerAtPath(path); }*/ float x = stateZeroPosition.x + stateXScale; GenerateTriggerableTransition("None", controller, new Vector3(x, stateZeroPosition.y), isLoop: true); GenerateTriggerableTransition("Close", controller, new Vector3(x, stateZeroPosition.y - stateYScale * 1), isLoop: false); GenerateTriggerableTransition("Idle", controller, new Vector3(x, stateZeroPosition.y - stateYScale * 2), false, isLoop: true); GenerateTriggerableTransition("Open", controller, new Vector3(x, stateZeroPosition.y - stateYScale * 3), isLoop: false); AddExitTransition(controller, "Close", "None"); AddExitTransition(controller, "Open", "Idle"); AssetDatabase.SaveAssets(); AssetDatabase.ImportAsset(path); return controller; } public static AnimatorController GetAnimController(RuntimeAnimatorController runtimeController) { var controller = AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(runtimeController)); return controller; } public static string GetSaveControllerPath(YKAnimatorListener target) { var defaultName = target.gameObject.name; var message = string.Format("Create a new animator for the game object '{0}':", defaultName); return EditorUtility.SaveFilePanelInProject("New Animation Contoller", defaultName, "controller", message); } public static AnimationClip GenerateTriggerableTransition(string name, AnimatorController controller, Vector3 position, bool writeDefault = true, bool isLoop = false) { // Create the clip var clip = AnimatorController.AllocateAnimatorClip(name); AssetDatabase.AddObjectToAsset(clip, controller); clip.wrapMode = isLoop ? WrapMode.Loop : WrapMode.Once; // Create a state in the animatior controller for this clip //var state = controller.AddMotion(clip); // Add a transition property controller.AddParameter(name, AnimatorControllerParameterType.Trigger); // Add an any state transition var stateMachine = controller.layers[0].stateMachine; var state = stateMachine.AddState(name, position); state.motion = clip; state.writeDefaultValues = writeDefault; var transition = stateMachine.AddAnyStateTransition(state); transition.canTransitionToSelf = false; transition.duration = 0; transition.AddCondition(AnimatorConditionMode.If, 0, name); return clip; } public static AnimationClip GenerateTriggerableTransition(string name, AnimatorController controller, bool writeDefault = true) { // Create the clip var clip = AnimatorController.AllocateAnimatorClip(name); AssetDatabase.AddObjectToAsset(clip, controller); // Create a state in the animatior controller for this clip //var state = controller.AddMotion(clip); // Add a transition property controller.AddParameter(name, AnimatorControllerParameterType.Trigger); // Add an any state transition var stateMachine = controller.layers[0].stateMachine; var state = stateMachine.AddState(name); state.motion = clip; state.writeDefaultValues = writeDefault; var transition = stateMachine.AddAnyStateTransition(state); transition.duration = 0; transition.AddCondition(AnimatorConditionMode.If, 0, name); return clip; } public static void AddExitTransition(AnimatorController controller, string stateNameFrom, string stateNameTo) { var stateMachine = controller.layers[0].stateMachine; AnimatorState stateFrom = null; AnimatorState stateTo = null; foreach(var state in stateMachine.states) { if(state.state.name.Equals(stateNameFrom)) { stateFrom = state.state; } if(state.state.name.Equals(stateNameTo)) { stateTo = state.state; } } var transition = stateFrom.AddTransition(stateTo); transition.duration = 0; transition.hasExitTime = true; transition.exitTime = 1f; } private static List defaultStates = new List() { "None", }; public static List GetAdditionStates(AnimatorController controller) { List result = new List(); if(controller != null) { var childStates = controller.layers[0].stateMachine.states; foreach(var state in childStates) { if(!defaultStates.Contains(state.state.name)) { result.Add(state.state); } } } return result; } public static bool DeleteAnimation(string animName, AnimatorController controller) { if(!EditorUtility.DisplayDialog("删除动画", string.Format("是否删除{0}", animName), "确定", "取消")) { return false; } AnimationClip clip = null; foreach(var anim in controller.animationClips) { if(anim.name.Equals(animName)) { clip = anim; } } if(clip != null) { string controllerPath = AssetDatabase.GetAssetPath(controller); string clipPath = AssetDatabase.GetAssetPath(clip); bool isSub = AssetDatabase.IsSubAsset(clip); if(isSub && controllerPath.Equals(clipPath)) { AssetDatabase.RemoveObjectFromAsset(clip); Object.DestroyImmediate(clip); DeleteStateAndTrigger(animName, controller); Debug.LogFormat("Delete {0}", animName); return true; } } return false; } private static void DeleteStateAndTrigger(string animName, AnimatorController controller) { foreach(var parameter in controller.parameters) { if(parameter.name.Equals(animName)) { controller.RemoveParameter(parameter); break; } } var stateMachine = controller.layers[0].stateMachine; foreach(var childState in stateMachine.states) { if(childState.state.name.Equals(animName)) { stateMachine.RemoveState(childState.state); } } } } //UI part public partial class YKAnimatorEditorUtility { public static void DrawAnimatorCustomStates(AnimatorController controller, ref string newStateName, ref Vector2 scrollPosState) { UEditorGUILayout.Label(AssetDatabase.GetAssetPath(controller)); var states = YKAnimatorEditorUtility.GetAdditionStates(controller); bool isDirty = false; string deleteStateName = ""; if(states.Count == 0) { EditorGUILayout.HelpBox("No Addition States", MessageType.Info); } else { scrollPosState = EditorGUILayout.BeginScrollView(scrollPosState, false, true, GUILayout.Height(120)); foreach(var state in states) { EditorGUILayout.BeginHorizontal(); if(UEditorGUILayout.Button(state.name)) { if(state.motion != null) { EditorGUIUtility.PingObject(state.motion); } } if(UEditorGUILayout.Button("X")) { deleteStateName = state.name; } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); } if(!string.IsNullOrEmpty(deleteStateName)) { isDirty |= YKAnimatorEditorUtility.DeleteAnimation(deleteStateName, controller); } EditorGUILayout.BeginHorizontal(); newStateName = EditorGUILayout.TextField(new GUIContent("Name"), newStateName).TrimStart().TrimEnd(); EditorGUI.BeginDisabledGroup(string.IsNullOrEmpty(newStateName)); { if(GUILayout.Button("Add Animation")) { if(string.IsNullOrEmpty(newStateName)) { Debug.LogError("animation state name is empty!"); } else { //float x = stateZeroPosition.x + stateXScale; //float y = stateZeroPosition.y - stateYScale * (states.Count + 4); //GenerateTriggerableTransition(newStateName, controller, new Vector3(x, y)); YKAnimatorEditorUtility.GenerateTriggerableTransition(newStateName, controller); Debug.LogFormat("Add {0}", newStateName); newStateName = ""; isDirty = true; } } } EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); if(isDirty) { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } } } }