其他分享
首页 > 其他分享> > 监听AnimationClip的开始和结束

监听AnimationClip的开始和结束

作者:互联网

# 实现要点:Unity的动画不管是Animation(legncy)或Animator都没有提供监听动画开始或结束的接口,不过他的AnimationClip可以在某一帧上添加event,event触发时可以调用某个函数,

这边就是利用了这个功能,来实现监听的。监听开始就是第1帧加个事件,监听结束就是在最后一帧加个事件(使用AnimationClip.AddEvent函数)。

 

public class AnimClipTimePositionListeners : MonoBehaviour
{

    public class TimePositionEvent : UnityEvent<AnimationEvent> { }

    const int Time_Position_Scale = 100000;

    struct ListenersKey
    {
        public AnimationClip _clip; //
        public int _timePosition; //监听某个clip的不同时间

        public ListenersKey(AnimationClip clip, float timePosition)
        {
            _clip = clip;
            _timePosition = (int)(timePosition * Time_Position_Scale);
        }
    }

    Dictionary<ListenersKey, TimePositionEvent> _listenersDict = new Dictionary<ListenersKey, TimePositionEvent>();

    public void OnEvent(AnimationEvent evt)
    {
        //Debug.Log($"OnEvent: AnimationEvent");

        var clip = evt.animatorClipInfo.clip;
        var timePosition = evt.time;
        var key = new ListenersKey(clip, timePosition);
        if (_listenersDict.TryGetValue(key, out var tpe))
        {
            tpe.Invoke(evt);
        }
    }

    public void AddListener(AnimationClip clip, float timePosition, UnityAction<AnimationEvent> l)
    {
        if (timePosition < 0)
            Debug.LogError($"timePos < 0: {timePosition}");

        var key = new ListenersKey(clip, timePosition);
        if (!_listenersDict.TryGetValue(key, out var tpe))
        {
            tpe = new TimePositionEvent();
            _listenersDict.Add(key, tpe);
        }
        tpe.AddListener(l);
    }

    public void RemoveListener(AnimationClip clip, float timePosition, UnityAction<AnimationEvent> l)
    {
        if (timePosition < 0)
            Debug.LogError($"timePos < 0: {timePosition}");

        var key = new ListenersKey(clip, timePosition);
        if (_listenersDict.TryGetValue(key, out var tpe))
        {
            tpe.RemoveListener(l);
        }
    }

    public void RemoveAllListeners(AnimationClip clip, float timePosition)
    {
        var key = new ListenersKey(clip, timePosition);
        if (_listenersDict.TryGetValue(key, out var tpe))
        {
            tpe.RemoveAllListeners();
        }
    }

    public static bool TryGetAnimatorClip(Animator animator, string clipName, out AnimationClip outClip)
    {
        var clips = animator.runtimeAnimatorController.animationClips;
        for (var i = 0; i < clips.Length; ++i)
        {
            var clip = clips[i];
            if (clip.name == clipName)
            {
                outClip = clip;
                return true;
            }
        }

        outClip = null;
        return false;
    }

    public static bool TryGetAnimatorClip(AnimatorClipInfo[] clipInfo, string clipName, out AnimationClip outClip)
    {
        for (var i = 0; i < clipInfo.Length; ++i)
        {
            var clip = clipInfo[i].clip;
            if (clip.name == clipName)
            {
                outClip = clip;
                return true;
            }
        }

        outClip = null;
        return false;
    }

    static bool IsTimePositionEquals(float t1, float t2)
    {
        return ((int)t1 * Time_Position_Scale) == ((int)t2 * Time_Position_Scale);
    }

    public static bool TryGetClipAnimationEvent(AnimationClip clip, float timePosition, out AnimationEvent outEvt)
    {
        for (var i = 0; i < clip.events.Length; ++i)
        {
            var evt = clip.events[i];
            if ("OnEvent" == evt.functionName)
            {
                if (IsTimePositionEquals(evt.time, timePosition))
                {
                    outEvt = evt;
                    return true;
                }
            }
        }
        outEvt = null;
        return false;
    }

    private bool TryGetAnimationEvent(int layerIndex, string clipName, ref float timePosition, out AnimationClip clip, out AnimationEvent evt)
    {
        var animator = GetComponent<Animator>();
        var clipInfo = animator.GetCurrentAnimatorClipInfo(layerIndex);
        if (TryGetAnimatorClip(clipInfo, clipName, out clip))
        {
            if (timePosition < 0)
                timePosition = clip.length;

            if (!TryGetClipAnimationEvent(clip, timePosition, out evt))
            {
                evt = new AnimationEvent();
                evt.functionName = "OnEvent";
                evt.time = timePosition;
                clip.AddEvent(evt);
            }
            return true;
        }

        clip = null;
        evt = null;
        return false;
    }


    public void AddListener(int layerIndex, string clipName, float timePosition, UnityAction<AnimationEvent> l)
    {
        if (TryGetAnimationEvent(layerIndex, clipName, ref timePosition, out var clip, out var evt))
        {
            AddListener(clip, timePosition, l);
        }
        else
        {
            Debug.LogError($"clip not exist: layer:{layerIndex}, name:{clipName}");
        }
    }

    public void RemoveListener(int layerIndex, string clipName, float timePosition, UnityAction<AnimationEvent> l)
    {
        if (TryGetAnimationEvent(layerIndex, clipName, ref timePosition, out var clip, out var evt))
        {
            RemoveListener(clip, timePosition, l);
        }
        else
        {
            Debug.LogError($"clip not exist: layer:{layerIndex}, name:{clipName}");
        }
    }

    public void RemoveAllListeners(int layerIndex, string clipName, float timePosition)
    {
        if (TryGetAnimationEvent(layerIndex, clipName, ref timePosition, out var clip, out var evt))
        {
            RemoveAllListeners(clip, timePosition);
        }
        else
        {
            Debug.LogError($"clip not exist: layer:{layerIndex}, name:{clipName}");
        }
    }

}

# 注册监听

public class Test : MonoBehaviour
{

    public AnimClipTimePositionListeners listeners;

    void Start()
    {
        listeners.AddListener(0, "New Animation", 0, (evt) =>
        {
            Debug.Log($"start");
        });

        listeners.AddListener(0, "New Animation", -1, (evt) =>
        {
            Debug.Log($"end");
        });
    }

}

 

标签:结束,AnimationClip,timePosition,public,clip,var,evt,监听,out
来源: https://www.cnblogs.com/sailJs/p/16459206.html