Unity Toggle 关联动画事件

原因

Unity GUI 里的 Button 可以通过更改 Transition 类型为动画来关联动画事件,Toggle 组件也可以,但是这些动画事件不是 Toggle 值变化时的通知事件,所以需要专门的通知动画事件。

解决

简单的脚本来实现,主要是编辑器部分借鉴使用 SelectableEditor 的代码。完整代码如下:

using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Toggle))]
[RequireComponent(typeof(Animator))]
public class ToggleAnimatorTrigger : MonoBehaviour
{
    private const string kDefaultOnAnimName = "On";
    private const string kDefaultOffAnimName = "Off";

    [SerializeField]
    private string m_OnTrigger = kDefaultOnAnimName;

    [SerializeField]
    private string m_OffTrigger = kDefaultOffAnimName;

    private Animator m_Animator;
    private Toggle m_Toggle;

    void Awake()
    {
        m_Animator = GetComponent<Animator>();
        m_Toggle = GetComponent<Toggle>();
        m_Toggle.onValueChanged.AddListener(OnToggleValueChanged);
    }

    private void OnToggleValueChanged(bool on)
    {
        m_Animator.ResetTrigger(m_OnTrigger);
        m_Animator.ResetTrigger(m_OffTrigger);
        m_Animator.SetTrigger(on ? m_OnTrigger : m_OffTrigger);
    }
}

编辑器代码:

using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;

[CustomEditor(typeof(ToggleAnimatorTrigger))]
public class ToggleAnimatorTriggerEditor : Editor
{
    SerializedProperty m_OnTriggerProperty;
    SerializedProperty m_OffTriggerProperty;

    void OnEnable()
    {
        m_OnTriggerProperty = serializedObject.FindProperty("m_OnTrigger");
        m_OffTriggerProperty = serializedObject.FindProperty("m_OffTrigger");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        var go = (target as ToggleAnimatorTrigger).gameObject;
        var animator = go.GetComponent<Animator>();

        EditorGUILayout.LabelField("Transition", "Animation");
        ++EditorGUI.indentLevel;
        {
            EditorGUILayout.PropertyField(m_OnTriggerProperty);
            EditorGUILayout.PropertyField(m_OffTriggerProperty);

            if (animator == null || animator.runtimeAnimatorController == null)
            {
                Rect buttonRect = EditorGUILayout.GetControlRect();
                buttonRect.xMin += EditorGUIUtility.labelWidth;
                if (GUI.Button(buttonRect, "Auto Generate Animation", EditorStyles.miniButton))
                {
                    var controller = GenerateSelectableAnimatorContoller(m_OnTriggerProperty.stringValue,
                        m_OffTriggerProperty.stringValue , go);
                    if (controller != null)
                    {
                        if (animator == null)
                            animator = go.AddComponent<Animator>();

                        AnimatorController.SetAnimatorController(animator, controller);
                    }
                }
            }
        }
        --EditorGUI.indentLevel;
        serializedObject.ApplyModifiedProperties();
    }

    private static AnimatorController GenerateSelectableAnimatorContoller(string onTrigger, string offTrigger, GameObject target)
    {
        if (target == null)
            return null;

        // Where should we create the controller?
        var path = GetSaveControllerPath(target);
        if (string.IsNullOrEmpty(path))
            return null;

        // Create controller and hook up transitions.
        var controller = AnimatorController.CreateAnimatorControllerAtPath(path);
        GenerateTriggerableTransition(onTrigger, controller);
        GenerateTriggerableTransition(offTrigger, controller);

        AssetDatabase.ImportAsset(path);

        return controller;
    }

    private static string GetSaveControllerPath(GameObject target)
    {
        var defaultName = target.gameObject.name;
        var message = string.Format("Create a new animator for the game object '{0}':", defaultName);
        return EditorUtility.SaveFilePanelInProject("New Animation Contoller", defaultName, "controller", message);
    }

    private static AnimationClip GenerateTriggerableTransition(string name, AnimatorController controller)
    {
        // Create the clip
        var clip = AnimatorController.AllocateAnimatorClip(name);
        AssetDatabase.AddObjectToAsset(clip, controller);

        // Create a state in the animatior controller for this clip
        var state = controller.AddMotion(clip);

        // Add a transition property
        controller.AddParameter(name, AnimatorControllerParameterType.Trigger);

        // Add an any state transition
        var stateMachine = controller.layers[0].stateMachine;
        var transition = stateMachine.AddAnyStateTransition(state);
        transition.AddCondition(AnimatorConditionMode.If, 0, name);
        transition.exitTime = 1f;
        transition.duration = 0f;
        return clip;
    }
}

截图如下:


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值