Unity自动生成AnimatorController
上一篇写了如何自动切割动画,这一篇写如何自动生成AnimatorController。
之前网上查了很多资料,看的一直很蒙,看不懂是怎么回事的,这里我先给大家明确几个概念:
画的不好,大家将就着看,写这个工具我们会涉及到很多类,类名包含上图哪个关键字,这个东西就跟哪个东西有关
只要大家能明确这些概念,看懂代码就不难了,下面上代码:
1 using UnityEngine; 2 using UnityEditor; 3 using System.IO; 4 using UnityEditor.Animations; 5 6 public class CreatePrefab : EditorWindow 7 { 8 #region -- 变量定义 9 private static string mOutputPath = ""; 10 private static bool mIsCreateAnimatorController = true; 11 12 private static AnimationClip mStart; 13 private static AnimationClip mTake; 14 private static AnimationClip mEnd; 15 #endregion 16 17 #region -- 系统函数 18 private void OnGUI() 19 { 20 GUILayout.BeginVertical(); 21 22 //绘制标题 23 GUILayout.Space(10); 24 GUI.skin.label.fontSize = 24; 25 GUI.skin.label.alignment = TextAnchor.MiddleCenter; 26 GUILayout.Label("Create Prefabs"); 27 28 //绘制文本 29 GUILayout.Space(10); 30 mOutputPath = EditorGUILayout.TextField("Output Path:", mOutputPath); 31 32 GUILayout.Space(10); 33 mIsCreateAnimatorController = EditorGUILayout.Toggle("Create AnimaControl:", mIsCreateAnimatorController); 34 35 if (GUILayout.Button("Create")) 36 { 37 CreatePrefabs(); 38 } 39 40 GUILayout.EndVertical(); 41 } 42 #endregion 43 44 #region -- 自定义函数 45 public static void CreateWindow() 46 { 47 //绘制窗口 48 EditorWindow.GetWindow(typeof(CreatePrefab), true, "Create Prefabs"); 49 } 50 private static void CreatePrefabs() 51 { 52 Object[] _objs = Selection.GetFiltered(typeof(GameObject), SelectionMode.Unfiltered); 53 if (_objs.Length == 0) 54 { 55 Debug.Log("你没有选择任何物体!"); 56 return; 57 } 58 for (int i = 0; i < _objs.Length; i++) 59 { 60 if (!Directory.Exists(Application.dataPath + "/" + mOutputPath)) 61 { 62 Directory.CreateDirectory(Application.dataPath + "/" + mOutputPath); 63 } 64 GameObject _temObJ = _objs[i] as GameObject; 65 string _outputPath = ""; 66 if (mOutputPath == "") 67 { 68 _outputPath = "Assets/"; 69 } 70 else 71 { 72 _outputPath = "Assets/" + mOutputPath + "/"; 73 } 74 GameObject _prefab = PrefabUtility.CreatePrefab(_outputPath + _temObJ.name + ".prefab", _temObJ); 75 if (mIsCreateAnimatorController) 76 { 77 AnimatorController _animatorController = CreateAnimatorController(AssetDatabase.GetAssetPath(_objs[i]), _temObJ.name + ".controller", _outputPath + "AnimatorControllers"); 78 Animator _animator = _prefab.GetComponent<Animator>(); 79 if (_animator != null) 80 { 81 _animator.runtimeAnimatorController = _animatorController; 82 } 83 } 84 } 85 AssetDatabase.Refresh(); 86 } 87 private static AnimatorController CreateAnimatorController(string _assetsPath, string _controllerName, string _outPutPath) 88 { 89 //创建AnimatorController文件,保存在_outPutPath路径下 90 if (!Directory.Exists(_outPutPath)) 91 { 92 Directory.CreateDirectory(_outPutPath); 93 } 94 95 //生成动画控制器(AnimatorController) 96 AnimatorController _animatorController = AnimatorController.CreateAnimatorControllerAtPath(_outPutPath + "/" + _controllerName); 97 98 //添加参数(parameters) 99 _animatorController.AddParameter("Normal", AnimatorControllerParameterType.Float); 100 _animatorController.AddParameter("Play", AnimatorControllerParameterType.Bool); 101 102 //得到它的Layer, 默认layer为base,可以拓展 103 AnimatorControllerLayer _layer = _animatorController.layers[0]; 104 105 //把动画文件保存在我们创建的AnimatorController中 106 AddStateTransition(_assetsPath, _layer); 107 return _animatorController; 108 } 109 private static void AddStateTransition(string _assetsPath, AnimatorControllerLayer _layer) 110 { 111 //添加动画状态机(这里只是通过层得到根状态机,并未添加) 112 AnimatorStateMachine _stateMachine = _layer.stateMachine; 113 114 // 根据动画文件读取它的AnimationClip对象 115 var _datas = AssetDatabase.LoadAllAssetsAtPath(_assetsPath); 116 if (_datas.Length == 0) 117 { 118 Debug.Log(string.Format("Can't find clip in {0}", _assetsPath)); 119 return; 120 } 121 122 // 遍历读取模型中包含的动画片段 123 foreach (var _data in _datas) 124 { 125 if (!(_data is AnimationClip)) 126 { 127 continue; 128 } 129 AnimationClip _newClip = _data as AnimationClip; 130 switch (_newClip.name) 131 { 132 case "Start": 133 mStart = _newClip; 134 break; 135 case "End": 136 mEnd = _newClip; 137 break; 138 case "Take": 139 mTake = _newClip; 140 break; 141 } 142 } 143 144 // 先添加一个默认的空状态 145 AnimatorState _emptyState = _stateMachine.AddState("Empty", new Vector3(_stateMachine.entryPosition.x + 200, _stateMachine.entryPosition.y, 0)); 146 147 // 添加与动画名称对应的装态(AnimatorState)到状态机中(AnimatorStateMachine)中,并设置状态 148 AnimatorState _startState = _stateMachine.AddState(mStart.name, new Vector3(_stateMachine.entryPosition.x + 500, _stateMachine.entryPosition.y + 100, 0)); 149 _startState.motion = mStart; 150 151 AnimatorState _endState = _stateMachine.AddState(mEnd.name, new Vector3(_stateMachine.entryPosition.x + 500, _stateMachine.entryPosition.y - 100, 0)); 152 _endState.motion = mEnd; 153 154 AnimatorState _take01State = _stateMachine.AddState("Take01", new Vector3(_stateMachine.entryPosition.x + 800, _stateMachine.entryPosition.y + 100, 0)); 155 _take01State.motion = mTake; 156 157 AnimatorState _take02State = _stateMachine.AddState("Take02", new Vector3(_stateMachine.entryPosition.x + 800, _stateMachine.entryPosition.y - 100, 0)); 158 _take02State.motion = mTake; 159 _take02State.speed = -1; 160 161 //连接每个状态,并添加切换条件 162 AnimatorStateTransition _animatorStateTransition = _emptyState.AddTransition(_startState); 163 _animatorStateTransition.AddCondition(AnimatorConditionMode.Greater, 0, "Normal"); 164 _animatorStateTransition.hasExitTime = false; 165 _animatorStateTransition.duration = 0; 166 167 _animatorStateTransition = _emptyState.AddTransition(_endState); 168 _animatorStateTransition.AddCondition(AnimatorConditionMode.Less, 0, "Normal"); 169 _animatorStateTransition.hasExitTime = false; 170 _animatorStateTransition.duration = 0; 171 172 _animatorStateTransition = _startState.AddTransition(_take01State); 173 _animatorStateTransition.AddCondition(AnimatorConditionMode.If, 0, "Play"); 174 _animatorStateTransition.hasExitTime = false; 175 _animatorStateTransition.duration = 0; 176 177 _animatorStateTransition = _endState.AddTransition(_take02State); 178 _animatorStateTransition.AddCondition(AnimatorConditionMode.If, 0, "Play"); 179 _animatorStateTransition.hasExitTime = false; 180 _animatorStateTransition.duration = 0; 181 } 182 #endregion 183 184 }
代码很详细了,也写了很多注释,这里就不多说了,大家自己看。
有个坑和大家说一下,我们是有 bool 类型的参数,如何设置 bool 类型的参数呢?
我开始天真的以为是这样的:
_animatorStateTransition.AddCondition(AnimatorConditionMode.If, 0, "BoolParameter");
_animatorStateTransition.AddCondition(AnimatorConditionMode.If, 1, "BoolParameter");
不知道有多少同学和我一样,有这种天真的想法,然后你会发现这样设置根本没用,值全部都为True,根本设置不了false
后来查了好久资料,才发现是这样设置 bool 类型的参数的:
_animatorStateTransition.AddCondition(AnimatorConditionMode.If, 0, "BoolParameter"); 为True
_animatorStateTransition.AddCondition(AnimatorConditionMode.IfNot, 0, "BoolParameter");为False
实在是坑,不想说话。。。。。。。
附上一张效果图
填写好输出路径,在 Project 视图中选中模型,点击 Create 按钮吧,然后你会发现预制体以及动画状态机都帮你制作好了,嘿嘿!
然后状态之间具体怎么连,这部分是需要自己根据项目需求自己写的,我这里只是给大家一个例子。