EditorでAnimatorの再生 その2
前回(EditorでAnimatorの再生 その1)、Animator.UpdateによるAnimatorの再生を行いました。今回は、EditorWindowへAnimatorに設定されているパラメーターを表示し、それらを変更することでアニメーションの遷移を行う機能を追加しました。
Script
作成したScriptは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
using System.Collections; using System.Collections.Generic; using System; using UnityEngine; using UnityEditor; namespace Karakan { public class AnimatorPlayerB : EditorWindow { GameObject _go_target; Animator _animator; TimeController _time_controller; Action<float> _action_play_animator; Action<int[], float> _action_init_animator; bool _flg_play = false, _flg_pause = false, _flg_stop = false, _flg_delay_pause = false, _flg_lock = false; int[] _default_state_hashes; float _play_speed = 1f; string _target_name = "None"; AnimatorControllerParameter[] _animator_controller_param; //gui GUIContent _content_play_button = new GUIContent(); GUIContent _content_pause_button = new GUIContent(); GUIStyle _style_toolbar_button; int _border_line_width = 1; [MenuItem("Tools/AnimatorPlayerB")] public static void OpenWindow() { EditorWindow ed = EditorWindow.GetWindow(typeof(AnimatorPlayerB), false, "AnimatorPlayerB"); ed.minSize = new Vector2(200, 456); } private void OnEnable() { _time_controller = new TimeController(); _content_play_button.image = EditorGUIUtility.Load("PlayButton") as Texture; _content_pause_button.image = EditorGUIUtility.Load("PauseButton") as Texture; _style_toolbar_button = new GUIStyle(EditorStyles.toolbarButton); _action_play_animator = (delta_time) => { if (_animator == null) return; _animator.Update(delta_time); }; _action_init_animator = (def_state_hash, time) => { for (int i = 0; i < def_state_hash.Length; i++) { _animator.Play(def_state_hash[i], -1, time); } }; } private void OnDisable() { if (_animator != null) { _action_init_animator(_default_state_hashes, 0f); _action_play_animator(1f); } } public void OnSelectionChange() { if (!_flg_lock) { _go_target = Selection.activeGameObject; Repaint(); } else { return; } if (_go_target == null) { _go_target = null; _animator = null; _target_name = "None"; return; } _animator = _go_target.GetComponent<Animator>(); if (_animator == null) { _go_target = null; _target_name = "None"; return; } _target_name = _go_target.name; _animator.speed = 0f; //get default state hash int animator_layer_count = _animator.layerCount; _default_state_hashes = new int[animator_layer_count]; for (int i = 0; i < animator_layer_count; i++) { AnimatorStateInfo anim_info = _animator.GetCurrentAnimatorStateInfo(i); _default_state_hashes[i] = anim_info.fullPathHash; } //get parameters _animator_controller_param = _animator.parameters; Repaint(); } private void OnGUI() { TimeControlUnit(); EditorGUILayout.LabelField("Selected GameObject:" + _target_name); BorderLine(_border_line_width); EditorGUILayout.LabelField("Parameters"); if (_animator != null) { for (int i = 0; i < _animator_controller_param.Length; i++) { switch (_animator_controller_param[i].type) { case AnimatorControllerParameterType.Bool: string bool_name = _animator_controller_param[i].name; bool flg = EditorGUILayout.Toggle(bool_name, _animator.GetBool(bool_name)); _animator.SetBool(bool_name, flg); break; case AnimatorControllerParameterType.Float: string float_name = _animator_controller_param[i].name; float float_val = EditorGUILayout.FloatField(float_name, _animator.GetFloat(float_name)); _animator.SetFloat(float_name, float_val); break; case AnimatorControllerParameterType.Int: string int_name = _animator_controller_param[i].name; int int_val = EditorGUILayout.IntField(int_name, _animator.GetInteger(int_name)); _animator.SetInteger(int_name, int_val); break; case AnimatorControllerParameterType.Trigger: string trigger_name = _animator_controller_param[i].name; if (GUILayout.Button(trigger_name)) { _animator.SetTrigger(trigger_name); } break; } } } } void TimeControlUnit() { if (_animator == null) return; Event ev = Event.current; _time_controller.speed = _play_speed; //コントロール用toolbar int toolbar_button_width = 50; EditorGUILayout.BeginHorizontal(); { //Play/Stop EditorGUI.BeginChangeCheck(); bool temp_flg_play = GUILayout.Toggle(_flg_play, _content_play_button, _style_toolbar_button, GUILayout.Width(toolbar_button_width)); if (ev.button == 0) _flg_play = temp_flg_play; if (EditorGUI.EndChangeCheck()) { if (_flg_play) { _flg_pause = false; _time_controller.Play(); _animator.speed = _play_speed; } else { _time_controller.Stop(); _flg_pause = false; GUI.changed = true; _flg_stop = true; } } //Pause EditorGUI.BeginChangeCheck(); bool temp_flg_pause = GUILayout.Toggle(_flg_pause, _content_pause_button, _style_toolbar_button, GUILayout.Width(toolbar_button_width)); if (ev.button == 0) _flg_pause = temp_flg_pause; if (_flg_play == false && _time_controller.isPlay == false) _flg_pause = false; if (EditorGUI.EndChangeCheck()) { if (_flg_pause) { _time_controller.Pause(); _animator.speed = 0f; _flg_delay_pause = true; } else { if (_flg_play) { _time_controller.Play(); _animator.speed = _play_speed; } } } //再生時間 float time = _time_controller.time; int hour = (int)(time / 3600f); time -= hour * 3600f; int minutes = (int)(time / 60f); float sec = time - minutes * 60f; EditorGUILayout.LabelField(hour.ToString() + ":" + minutes.ToString() + ":" + sec.ToString("f3")); if (_flg_stop) { _time_controller.time = 0f; _animator.speed = 0f; _action_init_animator(_default_state_hashes, 0f); _flg_stop = false; } GUILayout.Box(GUIContent.none, _style_toolbar_button, GUILayout.ExpandWidth(true)); _flg_lock = GUILayout.Toggle(_flg_lock, new GUIContent("Lock"), _style_toolbar_button, GUILayout.Width(toolbar_button_width)); } EditorGUILayout.EndHorizontal(); if (_time_controller.isPlay) HandleUtility.Repaint(); } void BorderLine(int height) { GUILayout.Box(GUIContent.none, GUILayout.ExpandWidth(true), GUILayout.Height(height)); } private void Update() { if (_time_controller != null && _animator != null) { _time_controller.TimeUpdate(); _action_play_animator?.Invoke(Time.deltaTime); } } } } |
パラメーターの取得と表示
Aniamtor.parametersによってAnimetorに設定されているAnimatorControllerParameterを取得することができます。これを用いて各パラメーターの型に応じてコントロールの表示を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
AnimatorControllerParameter[] _animator_controller_param; public void OnSelectionChange() { ・・・ //get parameters _animator_controller_param = _animator.parameters; Repaint(); } private void OnGUI() { ・・・ if (_animator != null) { for (int i = 0; i < _animator_controller_param.Length; i++) { switch (_animator_controller_param[i].type) { case AnimatorControllerParameterType.Bool: string bool_name = _animator_controller_param[i].name; bool flg = EditorGUILayout.Toggle(bool_name, _animator.GetBool(bool_name)); _animator.SetBool(bool_name, flg); break; case AnimatorControllerParameterType.Float: string float_name = _animator_controller_param[i].name; float float_val = EditorGUILayout.FloatField(float_name, _animator.GetFloat(float_name)); _animator.SetFloat(float_name, float_val); break; case AnimatorControllerParameterType.Int: string int_name = _animator_controller_param[i].name; int int_val = EditorGUILayout.IntField(int_name, _animator.GetInteger(int_name)); _animator.SetInteger(int_name, int_val); break; case AnimatorControllerParameterType.Trigger: string trigger_name = _animator_controller_param[i].name; if (GUILayout.Button(trigger_name)) { _animator.SetTrigger(trigger_name); } break; } } } } |
Animatorの初期化
Animatorを読み込んだ際、Animator.GetCurrentAnimatorStateInfoによって各レイヤーのEntryに接続されているAnimation Stateの情報を取得します。この情報からAnimation Stateのハッシュを取得します。取得したハッシュを用いてAnimator.Playを実行することで初期化を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Action<int[], float> _action_init_animator; private void OnEnable() { ・・・ _action_init_animator = (def_state_hash, time) => { for (int i = 0; i < def_state_hash.Length; i++) { _animator.Play(def_state_hash[i], -1, time); } }; } public void OnSelectionChange() { ・・・ //get default state hash int animator_layer_count = _animator.layerCount; _default_state_hashes = new int[animator_layer_count]; for (int i = 0; i < animator_layer_count; i++) { AnimatorStateInfo anim_info = _animator.GetCurrentAnimatorStateInfo(i); _default_state_hashes[i] = anim_info.fullPathHash; } ・・・ } void TimeControlUnit() { ・・・ _action_init_animator(_default_state_hashes, 0f); ・・・ } |
再生時間
再生時間はUpdate内で計測しており、Layout→Repaint→Updateの順に実行されるためEditorWindowで表示される数値は1フレームの遅れが生じます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
private void OnGUI() { TimeControlUnit(); ・・・ } void TimeControlUnit() { ・・・ //再生時間 float time = _time_controller.time; //再生時間 float time = _time_controller.time; int hour = (int)(time / 3600f); time -= hour * 3600f; int minutes = (int)(time / 60f); float sec = time - minutes * 60f; EditorGUILayout.LabelField(hour.ToString() + ":" + minutes.ToString() + ":" + sec.ToString("f3")); ・・・ } private void Update() { if (_time_controller != null && _animator != null) { _time_controller.TimeUpdate(); ・・・ } } |
実行結果
以上のScriptを実行するにあたり作成したAnimatorControllerは以下の通りです。
実行結果は以下の通りです。Speedの変更によりStanding→Walking→Runing、トリガーによるジャンプができています。また、フェイスアニメーションも問題なくできておりAnimatorの再生に問題はないようです。ジャンプ中の一時停止及び再開も問題なくできており、Animatorの停止時に初期状態へ戻す処理も機能していることが分かります。
このコンテンツはユニティちゃんライセンス条項の元に提供されています
-
前の記事
EditorでAnimatorの再生 その1 2021.04.05
-
次の記事
RendererFeatureでMRT(Multiple Render Target) 2022.03.06
コメントを書く