上一篇写了如何自动切割动画,这一篇写如何自动生成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 按钮吧,然后你会发现预制体以及动画状态机都帮你制作好了,嘿嘿!
然后状态之间具体怎么连,这部分是需要自己根据项目需求自己写的,我这里只是给大家一个例子。