NRE的编程笔记

导航

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 按钮吧,然后你会发现预制体以及动画状态机都帮你制作好了,嘿嘿!

然后状态之间具体怎么连,这部分是需要自己根据项目需求自己写的,我这里只是给大家一个例子。

posted on 2018-10-25 10:59  NRE  阅读(4679)  评论(0编辑  收藏  举报