可快速执行动画
本来还是想吐槽一下,不过算了,要是让我重头开发游戏,可能并不会用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.youkuaiyun.com/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);
}
}
}
}
}