上一篇寫了如何自動切割動畫,這一篇寫如何自動生成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 按鈕吧,然后你會發現預制體以及動畫狀態機都幫你制作好了,嘿嘿!
然后狀態之間具體怎么連,這部分是需要自己根據項目需求自己寫的,我這里只是給大家一個例子。