可快速執行動畫
本來還是想吐槽一下,不過算了,要是讓我重頭開發遊戲,可能並不會用Animator
Animator作爲Unity的官方產品,存在很久,4.6.3版本已經存在,一直沒需要更新??歷史悠久,版本穩定,優點也很無敵(當然針無兩頭利,最大的優點永遠伴隨最大的缺點)
優點:
- 暫時,可見的最好的可視化狀態機(可視化不好被程序員控制,)
- 提供AnyState (悲劇的開始,不是單向狀態機,很靠程序員自律)
- 向上分多個Layer (同上)
- 每個狀態向下可自定義Behaviours (同上)
- 提供完整的Animator Controller API (可能底層是c++,每個API都不高級,都不好用,例如hashName等)
- 一般不出問題 (出了問題就完全不知道哪裏入手)
之前花了半天,寫了一個Helper,結果一個小弟覺得沒用,刪了,結果就是各種BUG,各種鬼畜,各種不播動畫就是無從解決
這裏分享一下之前的Inspector,方便美術使用,能快速發現動作的問題和調試
未必能全支持,但是下面這例子已經足夠複雜,各動畫均支持快速播放
/* Animator 快速播放
*
* Author: Sidney
* Last: 20200404
* - created
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;
[CustomEditor(typeof(Animator))]
public class AnimatorInspector : Editor
{
public class AnimInAnimator
{
public string name;
public AnimatorCondition[] conditions;
//public AnimatorCondition condition;
}
Animator _anim;
Dictionary<string,AnimInAnimator> _infos;
AnimatorController _ctl;
Dictionary<string, AnimatorControllerParameter> _params;
public bool clearAllState = true;
GUIStyle normalStyle;
GUIStyle pressStyle;
private void Awake()
{
_anim = target as Animator;
InitState();
//normalStyle = GUIStyle
}
void InitState()
{
_infos = new Dictionary<string, AnimInAnimator>();
_ctl = _anim.runtimeAnimatorController as AnimatorController;
AnimatorStateMachine stateMachine = _ctl.layers[0].stateMachine;
ChildAnimatorState[] animatorState = stateMachine.states;
_params = new Dictionary<string, AnimatorControllerParameter>();
foreach (var par in _ctl.parameters)
{
_params.Add(par.name, par);
}
//
foreach (var anyTransition in stateMachine.anyStateTransitions) {
AddState(anyTransition);
}
for (int i = 0; i < animatorState.Length; i++)
{
ChildAnimatorState state = animatorState[i];
var tranitions = state.state.transitions;
string srcName = state.state.name;
foreach (var tran in tranitions)
{
////只有出的transition(沒有入??) 所以通過"出"判斷
//string stateName = tran.destinationState.name;
//if (_infos.ContainsKey(stateName) == false)
//{
// AnimInAnimator data = new AnimInAnimator();
// data.name = stateName;
// data.conditions = tran.conditions;
// _infos.Add(stateName, data);
//}
var data = AddState(tran);
//判斷出輸入transition 所有、、???
Debug.Log(string.Format("{0}->{1}", srcName, data.name));
}
}
}
AnimInAnimator AddState(AnimatorStateTransition tran) {
//只有出的transition(沒有入??) 所以通過"出"判斷
string stateName = tran.destinationState.name;
AnimInAnimator data = null;
if (_infos.ContainsKey(stateName) == false)
{
data = new AnimInAnimator();
data.name = stateName;
data.conditions = tran.conditions;
_infos.Add(stateName, data);
}
else {
data = _infos[stateName];
}
return data;
}
public override void OnInspectorGUI()
{
if (!Application.isPlaying)
{
GUILayout.Label("運行後,才顯示執行動畫按鈕");
}
else
{
clearAllState = GUILayout.Toggle(clearAllState, "執行動畫前還原Animator參數", new GUILayoutOption[0]);
foreach (var data in _infos)
{
string animation = data.Value.name;
GUIStyleState s_state = new GUIStyleState();
string styleName = "button";
//if (_anim.GetCurrentAnimatorStateInfo(0).fullPathHash == animation)
//{
// s.name = "PreButtonBlue";
//}
//詳細測試可參考:https://blog.csdn.net/weixin_33896726/article/details/86216606
if (_anim.GetCurrentAnimatorStateInfo(0).shortNameHash == Animator.StringToHash(animation))
{
styleName = "PreButtonBlue";
}
if (GUILayout.Button(animation, styleName))
{
OnClearParams();
OnStateButtonClick(data.Value);
}
}
}
GUILayout.Space(5);
base.OnInspectorGUI();
}
void OnClearParams() {
if (clearAllState) {
foreach (var par in _params) {
AnimatorControllerParameter param = par.Value;
if (param.type == AnimatorControllerParameterType.Bool)
{
_anim.SetBool(param.name, param.defaultBool);
}
else if (param.type == AnimatorControllerParameterType.Float)
{
_anim.SetFloat(param.name, param.defaultFloat);
}
else if (param.type == AnimatorControllerParameterType.Int)
{
_anim.SetInteger(param.name, param.defaultInt);
}
}
}
}
void OnStateButtonClick(AnimInAnimator data_value)
{
if (data_value.conditions == null || data_value.conditions.Length == 0)
{
//如果沒條件,又想進入這個狀態。。。。。
}
else
{
//_anim.Play(animation);
foreach (var con in data_value.conditions)
{
string key = con.parameter;
float value = con.threshold;
var param = _params[key];
if (param.type == AnimatorControllerParameterType.Bool)
{
if (con.mode == AnimatorConditionMode.If)
{
_anim.SetBool(key, true);
}
else
{
_anim.SetBool(key, false);
}
}
else if (param.type == AnimatorControllerParameterType.Float)
{
if (con.mode == AnimatorConditionMode.Equals)
{
_anim.SetFloat(key, value);
}
else if (con.mode == AnimatorConditionMode.NotEqual)
{
_anim.SetFloat(key, value + 1);
}
else if (con.mode == AnimatorConditionMode.Greater)
{
_anim.SetFloat(key, value);
}
else if (con.mode == AnimatorConditionMode.Less)
{
_anim.SetFloat(key, value - 1);
}
else
{
Debug.LogError("Animator Set Float 應該不會出現這個情況 mode...=" + con.mode.ToString());
}
}
else if (param.type == AnimatorControllerParameterType.Int) {
if (con.mode == AnimatorConditionMode.Equals || con.mode == AnimatorConditionMode.Greater)
{
_anim.SetInteger(key, (int)value);
}
else if (con.mode == AnimatorConditionMode.Less || con.mode == AnimatorConditionMode.NotEqual)
{
_anim.SetInteger(key, (int)(value - 1));
}
else
{
Debug.LogError("Animator Set Int 應該不會出現這個情況 mode...=" + con.mode.ToString());
}
}
else if (param.type == AnimatorControllerParameterType.Trigger) {
_anim.SetTrigger(key);
}
}
}
}
}