ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

监听AnimationClip的开始和结束

2022-07-09 00:04:25  阅读:159  来源: 互联网

标签:结束 AnimationClip timePosition public clip var evt 监听 out


# 实现要点: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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有