赞
踩
利用AnimatorStateInfo信息来处理当前的动画信息。
目前没出现什么bug,回调也相对精准。
使用方式:
- Animator.SetTrigger("shoot", delegate() { });
- Animator.SetBool("enable", true, delegate() { });
- Animator.Play("shoot",delegate() { });
源码:实现方式1
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace KT.Core
- {
- /// <summary>
- /// Animator 播放动画回调相关
- /// </summary>
- public class AnimatorPlayCall : MonoBehaviour
- {
- List<AnimatorPlayCallParam> Pools = new List<AnimatorPlayCallParam>();
-
- static AnimatorPlayCall instance;
- public static AnimatorPlayCall I
- {
- get
- {
- if (instance == null)
- {
- instance = new GameObject("AnimatorPlayCall").AddComponent<AnimatorPlayCall>();
- GameObject.DontDestroyOnLoad(instance);
- }
- return instance;
- }
- }
-
- /// <summary>
- /// 检测Animator是否播放完毕
- /// </summary>
- /// <param name="animator"></param>
- /// <param name="name"></param>
- /// <param name="action"></param>
- public void OnIsPlayOver(Animator animator,bool isCurrent, System.Action action)
- {
- if (action == null)
- return;
- Pools.Add(new AnimatorPlayCallParam(animator, isCurrent, action));
- }
-
- void Update()
- {
- if (Pools.Count > 0)
- {
- for (int i = 0; i < Pools.Count; i++)
- {
- if (Pools[i].Check())
- {
- Pools.Remove(Pools[i]);
- }
- }
- }
- }
-
- /// <summary>
- /// 播放回调参数
- /// </summary>
- class AnimatorPlayCallParam
- {
- public AnimatorPlayCallParam(Animator animator, bool isCurrent, System.Action call)
- {
- Layer = 0;
- Action = call;
- Animator = animator;
- IsCurrent = isCurrent;
- }
-
- public AnimatorPlayCallParam(Animator animator, bool isCurrent,int layer, System.Action call)
- {
- Layer = layer;
- Action = call;
- Animator = animator;
- IsCurrent = isCurrent;
- }
-
- /// <summary>
- /// 层
- /// </summary>
- public int Layer { private set; get; }
-
- /// <summary>
- /// 回调行为
- /// </summary>
- public System.Action Action { private set; get; }
-
- /// <summary>
- /// Animator 动画
- /// </summary>
- public Animator Animator { private set; get; }
-
- /// <summary>
- /// 是否当前动画
- /// </summary>
- public bool IsCurrent { private set; get; }
-
- /// <summary>
- /// 缓存的NameHash
- /// </summary>
- private int shortNameHash=0;
-
- private AnimatorStateInfo CurInfo
- {
- get
- {
- return Animator.GetCurrentAnimatorStateInfo(Layer);
- }
- }
-
- private AnimatorStateInfo NextInfo
- {
- get
- {
- return Animator.GetNextAnimatorStateInfo(Layer);
- }
- }
-
- /// <summary>
- /// 每帧检测动画状态
- /// </summary>
- /// <returns></returns>
- public bool Check()
- {
- if (Action == null)
- return true;
- if(IsCurrent)
- {
- if(shortNameHash == 0 && CurInfo.shortNameHash != 0)
- {
- shortNameHash = CurInfo.shortNameHash;
- }
- }
- else
- {
- if (shortNameHash == 0 && NextInfo.shortNameHash != 0)
- {
- shortNameHash = NextInfo.shortNameHash;
- }
- }
- if (CurInfo.shortNameHash != shortNameHash && shortNameHash != NextInfo.shortNameHash)
- {
- Action?.Invoke();
- return true;
- }
- return false;
- }
- }
- }
-
- /// <summary>
- /// Animator扩展
- /// </summary>
- public static class AnimatorExtension
- {
- public static void SetTrigger(this Animator animater, string name, System.Action action)
- {
- animater.SetTrigger(name);
- AnimatorPlayCall.I.OnIsPlayOver(animater,false, action);
- }
-
- public static void SetBool(this Animator animater, string name, bool value, System.Action action)
- {
- animater.SetBool(name, value);
- AnimatorPlayCall.I.OnIsPlayOver(animater, false, action);
- }
-
- public static void Play(this Animator animater, string name, System.Action action)
- {
- animater.Play(name);
- AnimatorPlayCall.I.OnIsPlayOver(animater, true, action);
- }
-
- public static void OnOver(this Animator animater,bool isCurrent, System.Action action)
- {
- AnimatorPlayCall.I.OnIsPlayOver(animater, isCurrent, action);
- }
- }
-
- }
源码:实现方式2【目前自己用的方式】
- using System.Collections.Generic;
- using UnityEngine;
- namespace KTF.Extend.AnimatorOverCall
- {
- /// <summary>
- /// AnimatorOver完毕后回调管理
- /// </summary>
- public class AnimatorOverCallMgr
- {
- private AnimatorOverCallMgr() { }
- private static AnimatorOverCallMgr instance;
- public static AnimatorOverCallMgr I
- {
- get
- {
- if (instance == null)
- {
- instance = new AnimatorOverCallMgr();
- }
- return instance;
- }
- }
-
- private Dictionary<string, AnimatorCallElement> callManager = new Dictionary<string, AnimatorCallElement>();
-
- internal void HandleEvent(string name)
- {
- if (callManager.ContainsKey(name))
- {
- callManager[name].DoOver();
- }
- }
-
- internal void RemoveHandleEvent(string name)
- {
- if (callManager.ContainsKey(name))
- {
- callManager.Remove(name);
- }
- }
-
- internal void AddListener(Animator animator, System.Action call)
- {
- string c_InstanceID = animator.gameObject.GetInstanceID() + "";
- if (!callManager.ContainsKey(c_InstanceID))
- {
- callManager.Add(c_InstanceID, new AnimatorCallElement(animator));
- }
- CheckEvent(animator, c_InstanceID);
-
- callManager[c_InstanceID].onOver -= call;
- callManager[c_InstanceID].onOver += call;
- }
-
- /// <summary>
- /// 添加一个监听
- /// </summary>
- /// <param name="animator"></param>
- /// <param name="call">返回值是(Layer,StateNameHash)</param>
- public void AddListener(Animator animator, System.Action<int,int> call)
- {
- string c_InstanceID = animator.gameObject.GetInstanceID() + "";
- if (!callManager.ContainsKey(c_InstanceID))
- {
- callManager.Add(c_InstanceID, new AnimatorCallElement(animator));
- }
- CheckEvent(animator, c_InstanceID);
-
- callManager[c_InstanceID].onOverByStateNameHash -= call;
- callManager[c_InstanceID].onOverByStateNameHash += call;
- }
-
- /// <summary>
- /// 移除一个监听
- /// </summary>
- /// <param name="animator"></param>
- /// <param name="call"></param>
- public void RemoveListener(Animator animator, System.Action<int,int> call)
- {
- string c_InstanceID = animator.gameObject.GetInstanceID() + "";
- if (callManager.ContainsKey(c_InstanceID))
- {
- callManager[c_InstanceID].onOverByStateNameHash -= call;
- }
- }
-
- AnimationClip[] c_clips;
- AnimationEvent[] c_events;
- /// <summary>
- /// 检查是否有Event
- /// </summary>
- /// <param name="animator"></param>
- /// <param name="c_InstanceID"></param>
- private void CheckEvent(Animator animator,string c_InstanceID)
- {
- if (animator.GetComponent<AnimatorOverCall>() == null)
- {
- AnimatorOverCall animatorOverCall = animator.gameObject.AddComponent<AnimatorOverCall>();
- animatorOverCall.SetInstanceID(c_InstanceID);
- c_clips = animator.runtimeAnimatorController.animationClips;
- for (int i = 0,length = c_clips.Length; i < length; i++)
- {
- if (c_clips[i] == null)
- {
- continue;
- }
- c_events = c_clips[i].events;
- for (int j = 0; j < c_events.Length; j++)
- {
- if (c_events[j] == null)
- {
- continue;
- }
- if (c_events[j].functionName == "OverCall")
- {
- return;
- }
- }
- c_clips[i].AddEvent(new AnimationEvent() { functionName = "OverCall", time = c_clips[i].length });
- }
- }
- }
-
- #region 内部类
- private class AnimatorCallElement
- {
- public AnimatorCallElement(Animator animator)
- {
- this.animator = animator;
- }
-
- private Animator animator;
-
- internal System.Action onOver;
-
- internal event System.Action<int, int> onOverByStateNameHash;
-
- internal void DoOver()
- {
- if (onOverByStateNameHash != null)
- {
- for (int i = 0, length = animator.layerCount; i < length; i++)
- {
- onOverByStateNameHash.Invoke(i, animator.GetCurrentAnimatorStateInfo(i).shortNameHash);
- }
- }
- onOver?.Invoke();
- onOver = null;
- }
- }
- #endregion
- }
-
- /// <summary>
- /// 对Animator扩展
- /// </summary>
- public static class AnimatorExtend
- {
- public static void Play(this Animator animator, string name, System.Action action,int layout=0)
- {
- if (animator.HasState(layout, Animator.StringToHash(name)))
- {
- animator.Play(name, layout);
- AnimatorOverCallMgr.I.AddListener(animator, action);
- }
- else
- {
- action?.Invoke();
- Debug.LogError("没有:" + name+"State");
- }
- }
-
- /// <summary>
- /// 添加完毕监听
- /// </summary>
- /// <param name="animater"></param>
- /// <param name="action">返回值是(Layer,StateNameHash)</param>
- public static void AddOverCall(this Animator animater, System.Action<int, int> action)
- {
- AnimatorOverCallMgr.I.AddListener(animater, action);
- }
-
- /// <summary>
- /// 移除完毕监听
- /// </summary>
- /// <param name="animater"></param>
- /// <param name="action"></param>
- public static void RemoveOverCall(this Animator animater, System.Action<int,int> action)
- {
- AnimatorOverCallMgr.I.RemoveListener(animater, action);
- }
- }
-
- [DisallowMultipleComponent]
- internal class AnimatorOverCall : MonoBehaviour
- {
- private string instanceID;
- internal void SetInstanceID(string id)
- {
- instanceID = id;
- }
- public void OverCall()
- {
- AnimatorOverCallMgr.I.HandleEvent(instanceID);
- }
-
- private void OnDestroy()
- {
- AnimatorOverCallMgr.I.RemoveHandleEvent(instanceID);
- }
- }
- }
-
更复杂的可以考虑StateMachineBehaviour!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。