处理animator动画播放
1、等待动画播放完成
yield return ani.OnPlay(“Idle”).OnWaitComplete();

2、动画播放完成执行
ani.OnPlay(“Idle”).OnComplete(() => xxx.SetActive(false));

3、等待动画播放进度到0.5f
yield return ani.OnPlay(“Idle”).OnWaitProgress(0.5f);

4、动画播放进度到0.5f执行
ani.OnPlay(“Idle”).OnProgress(()=> { xxx.SetActive(false)}, 0.5f);

5、触发事件
ani.OnPlay(“Jump”).OnTriggerEvent(() => { //处理触发事件; }, “JumpEventName”);

using UnityEngine;
using System;
using System.Collections;
using System.Threading.Tasks;

/// <summary>
///  Animator功能拓展
/// </summary>
public static class BXAnimatorUtil
{
    #region 状态
    /// <summary>
    /// 是否为激活状态
    /// </summary>
    public static bool IsActive(this Animator ani)
    {
        return ani.gameObject ? ani.gameObject.activeSelf : false;
    }

    /// <summary>
    /// 设置激活状态
    /// </summary>
    public static void SetActive(this Animator ani, bool value)
    {
        ani.gameObject?.SetActive(value);
    }
    #endregion


    #region 播放动画
    /// <summary>
    /// 播放动画-nameHash
    /// </summary>
    public static Animator OnPlay(this Animator ani, int nameHash)
    {
        ani?.Play(nameHash);
        return ani;
    }


    /// <summary>
    /// 异步播放动画-nameHash
    /// </summary>
    public static Animator OnAsyncPlay(this Animator ani, int nameHash)
    {
        ani.AsyncPlay(nameHash);
        return ani;
    }

    /// <summary>
    /// 异步播放动画-nameHash
    /// </summary>
    public static async void AsyncPlay(this Animator ani, int nameHash)
    {
        await new WaitForEndOfFrame();
        ani?.Play(nameHash);
    }
    #endregion


    #region 播放动画
    /// <summary>
    /// 播放动画
    /// </summary>
    public static Animator OnPlay(this Animator ani, string name)
    {
        ani?.Play(name);
        return ani;
    }

    /// <summary>
    /// 异步播放动画
    /// </summary>
    public static Animator OnAsyncPlay(this Animator ani, string name)
    {
        ani.AsyncPlay(name);
        return ani;
    }

    /// <summary>
    /// 异步播放动画
    /// </summary>
    public static async void AsyncPlay(this Animator ani, string name)
    {
        await new WaitForEndOfFrame();
        ani?.Play(name);
    }
    #endregion


    #region 动画播放进度
    /// <summary>
    /// 等待动画播放完成
    /// </summary>
    public static Task OnWaitComplete(this Animator ani)
    {
        return PlayCallBack(ani);
    }

    /// <summary>
    /// 动画播放完成
    /// </summary>
    public static void OnComplete(this Animator ani, Action call)
    {
        if (ani == null || call == null) return;
        PlayCallBack(ani, call);
    }

    /// <summary>
    /// 等待动画播放进度
    /// </summary>
    /// <param name="ani">动画控制器</param>
    /// <param name="progress">动画播放进度0-1</param>
    public static Task OnWaitProgress(this Animator ani, float progress)
    {
        return PlayCallBack(ani, null, progress);
    }

    /// <summary>
    /// 动画播放进度
    /// </summary>
    /// <param name="ani">动画控制器</param>
    /// <param name="progress">动画播放进度0-1</param>
    public static void OnProgress(this Animator ani, Action call, float progress)
    {
        if (ani == null) return;
        PlayCallBack(ani, call, progress);
    }

    /// <summary>
    /// 动画播放进度回调
    /// </summary>
    static async Task PlayCallBack(Animator ani, Action call = null, float progress = 1)
    {
        await new WaitForEndOfFrame();
        if (ani != null)
        {
            var clipInfo = ani.GetCurrentAnimatorStateInfo(0);
            await new WaitForSecondsRealtime(clipInfo.length * progress);
        }

        call?.Invoke();
    }
    #endregion


    #region 当前动画播放进度
    /// <summary>
    /// 当前动画播放完成
    /// </summary>
    public static void OnCurrentComplete(this Animator ani, Action call)
    {
        if (ani == null || call == null) return;
        PlayCurrentCallBack(ani, call);
    }

    /// <summary>
    /// 当前动画播放进度回调
    /// </summary>
    static async void PlayCurrentCallBack(Animator ani, Action call = null)
    {
        await new WaitForEndOfFrame();
        if (ani != null)
        {
            var clipInfo = ani.GetCurrentAnimatorStateInfo(0);
            var time = clipInfo.length * (1 - clipInfo.normalizedTime);
            await new WaitForSecondsRealtime(time);
        }
        call?.Invoke();
    }
    #endregion


    #region 动画触发事件
    /// <summary>
    ///动画触发事件
    /// </summary>
    public static Animator OnTriggerEvent(this Animator ani, Action call, string eventName)
    {
        if (ani != null)
        {
            ani.fireEvents = false;
            TriggerCallBack(ani, call, eventName);
        }
        return ani;
    }

    /// <summary>
    /// 动画触发事件回调
    /// </summary>
    static async void TriggerCallBack(Animator ani, Action call, string eventName)
    {
        await new WaitForEndOfFrame();
        if (ani != null)
        {
            float progress = GetCurEventProgress(ani, eventName);
            if (progress != -1)
            {
                var curState = ani.GetCurrentAnimatorStateInfo(0);
                if (curState.loop)//循环触发
                {
                    TriggerCallBackLoop(ani, curState, call, progress);
                }
                else//单次触发
                {
                    await new WaitForSecondsRealtime(curState.length * progress);
                    call?.Invoke();
                }
            }
            else
            {
                Debug.LogError($"Animator ani don't have AnimationEvent {eventName}");
            }
        }
    }

    /// <summary>
    /// Animation loop触发事件
    /// </summary>
    static async void TriggerCallBackLoop(Animator ani, AnimatorStateInfo lastState, Action call, float progress)
    {
        await new WaitForEndOfFrame();
        bool loop = lastState.loop;
        while (loop)
        {
            await new WaitForSecondsRealtime(lastState.length * progress);
            if (ani.GetCurrentAnimatorStateInfo(0).fullPathHash == lastState.fullPathHash) call?.Invoke();
            await new WaitForSecondsRealtime(lastState.length * (1 - progress));
            loop = lastState.loop && ani.GetCurrentAnimatorStateInfo(0).fullPathHash == lastState.fullPathHash;
        }
    }
    #endregion


    /// <summary>
    /// 获取Animator当前动画event.time
    /// </summary>
    public static float GetCurEventProgress(Animator ani, string mathName)
    {
        var curClip = ani.GetCurrentAnimatorClipInfo(0);
        if (curClip == null || curClip.Length <= 0) return -1;

        AnimationClip clip = curClip[0].clip;
        if (clip == null || clip.events.Length <= 0) return -1;

        AnimationEvent[] events = clip.events;
        for (int i = 0; i < events.Length; i++)
        {
            if (events[i].functionName == mathName)
            {
                return events[i].time;
            }
        }

        return -1;
    }

}
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐