真Unity3d_分享一個Animator幫助類

可快速執行動畫

本來還是想吐槽一下,不過算了,要是讓我重頭開發遊戲,可能並不會用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);
                }
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章