当前位置:   article > 正文

为Unity3D的Animator动画状态增加播放完毕回调_unity animator 回调

unity animator 回调

利用AnimatorStateInfo信息来处理当前的动画信息。

目前没出现什么bug,回调也相对精准。

使用方式:

  1. Animator.SetTrigger("shoot", delegate() { });
  2. Animator.SetBool("enable", true, delegate() { });
  3. Animator.Play("shoot",delegate() { });

 源码:实现方式1

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace KT.Core
  4. {
  5. /// <summary>
  6. /// Animator 播放动画回调相关
  7. /// </summary>
  8. public class AnimatorPlayCall : MonoBehaviour
  9. {
  10. List<AnimatorPlayCallParam> Pools = new List<AnimatorPlayCallParam>();
  11. static AnimatorPlayCall instance;
  12. public static AnimatorPlayCall I
  13. {
  14. get
  15. {
  16. if (instance == null)
  17. {
  18. instance = new GameObject("AnimatorPlayCall").AddComponent<AnimatorPlayCall>();
  19. GameObject.DontDestroyOnLoad(instance);
  20. }
  21. return instance;
  22. }
  23. }
  24. /// <summary>
  25. /// 检测Animator是否播放完毕
  26. /// </summary>
  27. /// <param name="animator"></param>
  28. /// <param name="name"></param>
  29. /// <param name="action"></param>
  30. public void OnIsPlayOver(Animator animator,bool isCurrent, System.Action action)
  31. {
  32. if (action == null)
  33. return;
  34. Pools.Add(new AnimatorPlayCallParam(animator, isCurrent, action));
  35. }
  36. void Update()
  37. {
  38. if (Pools.Count > 0)
  39. {
  40. for (int i = 0; i < Pools.Count; i++)
  41. {
  42. if (Pools[i].Check())
  43. {
  44. Pools.Remove(Pools[i]);
  45. }
  46. }
  47. }
  48. }
  49. /// <summary>
  50. /// 播放回调参数
  51. /// </summary>
  52. class AnimatorPlayCallParam
  53. {
  54. public AnimatorPlayCallParam(Animator animator, bool isCurrent, System.Action call)
  55. {
  56. Layer = 0;
  57. Action = call;
  58. Animator = animator;
  59. IsCurrent = isCurrent;
  60. }
  61. public AnimatorPlayCallParam(Animator animator, bool isCurrent,int layer, System.Action call)
  62. {
  63. Layer = layer;
  64. Action = call;
  65. Animator = animator;
  66. IsCurrent = isCurrent;
  67. }
  68. /// <summary>
  69. ///
  70. /// </summary>
  71. public int Layer { private set; get; }
  72. /// <summary>
  73. /// 回调行为
  74. /// </summary>
  75. public System.Action Action { private set; get; }
  76. /// <summary>
  77. /// Animator 动画
  78. /// </summary>
  79. public Animator Animator { private set; get; }
  80. /// <summary>
  81. /// 是否当前动画
  82. /// </summary>
  83. public bool IsCurrent { private set; get; }
  84. /// <summary>
  85. /// 缓存的NameHash
  86. /// </summary>
  87. private int shortNameHash=0;
  88. private AnimatorStateInfo CurInfo
  89. {
  90. get
  91. {
  92. return Animator.GetCurrentAnimatorStateInfo(Layer);
  93. }
  94. }
  95. private AnimatorStateInfo NextInfo
  96. {
  97. get
  98. {
  99. return Animator.GetNextAnimatorStateInfo(Layer);
  100. }
  101. }
  102. /// <summary>
  103. /// 每帧检测动画状态
  104. /// </summary>
  105. /// <returns></returns>
  106. public bool Check()
  107. {
  108. if (Action == null)
  109. return true;
  110. if(IsCurrent)
  111. {
  112. if(shortNameHash == 0 && CurInfo.shortNameHash != 0)
  113. {
  114. shortNameHash = CurInfo.shortNameHash;
  115. }
  116. }
  117. else
  118. {
  119. if (shortNameHash == 0 && NextInfo.shortNameHash != 0)
  120. {
  121. shortNameHash = NextInfo.shortNameHash;
  122. }
  123. }
  124. if (CurInfo.shortNameHash != shortNameHash && shortNameHash != NextInfo.shortNameHash)
  125. {
  126. Action?.Invoke();
  127. return true;
  128. }
  129. return false;
  130. }
  131. }
  132. }
  133. /// <summary>
  134. /// Animator扩展
  135. /// </summary>
  136. public static class AnimatorExtension
  137. {
  138. public static void SetTrigger(this Animator animater, string name, System.Action action)
  139. {
  140. animater.SetTrigger(name);
  141. AnimatorPlayCall.I.OnIsPlayOver(animater,false, action);
  142. }
  143. public static void SetBool(this Animator animater, string name, bool value, System.Action action)
  144. {
  145. animater.SetBool(name, value);
  146. AnimatorPlayCall.I.OnIsPlayOver(animater, false, action);
  147. }
  148. public static void Play(this Animator animater, string name, System.Action action)
  149. {
  150. animater.Play(name);
  151. AnimatorPlayCall.I.OnIsPlayOver(animater, true, action);
  152. }
  153. public static void OnOver(this Animator animater,bool isCurrent, System.Action action)
  154. {
  155. AnimatorPlayCall.I.OnIsPlayOver(animater, isCurrent, action);
  156. }
  157. }
  158. }

源码:实现方式2【目前自己用的方式】

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace KTF.Extend.AnimatorOverCall
  4. {
  5. /// <summary>
  6. /// AnimatorOver完毕后回调管理
  7. /// </summary>
  8. public class AnimatorOverCallMgr
  9. {
  10. private AnimatorOverCallMgr() { }
  11. private static AnimatorOverCallMgr instance;
  12. public static AnimatorOverCallMgr I
  13. {
  14. get
  15. {
  16. if (instance == null)
  17. {
  18. instance = new AnimatorOverCallMgr();
  19. }
  20. return instance;
  21. }
  22. }
  23. private Dictionary<string, AnimatorCallElement> callManager = new Dictionary<string, AnimatorCallElement>();
  24. internal void HandleEvent(string name)
  25. {
  26. if (callManager.ContainsKey(name))
  27. {
  28. callManager[name].DoOver();
  29. }
  30. }
  31. internal void RemoveHandleEvent(string name)
  32. {
  33. if (callManager.ContainsKey(name))
  34. {
  35. callManager.Remove(name);
  36. }
  37. }
  38. internal void AddListener(Animator animator, System.Action call)
  39. {
  40. string c_InstanceID = animator.gameObject.GetInstanceID() + "";
  41. if (!callManager.ContainsKey(c_InstanceID))
  42. {
  43. callManager.Add(c_InstanceID, new AnimatorCallElement(animator));
  44. }
  45. CheckEvent(animator, c_InstanceID);
  46. callManager[c_InstanceID].onOver -= call;
  47. callManager[c_InstanceID].onOver += call;
  48. }
  49. /// <summary>
  50. /// 添加一个监听
  51. /// </summary>
  52. /// <param name="animator"></param>
  53. /// <param name="call">返回值是(Layer,StateNameHash)</param>
  54. public void AddListener(Animator animator, System.Action<int,int> call)
  55. {
  56. string c_InstanceID = animator.gameObject.GetInstanceID() + "";
  57. if (!callManager.ContainsKey(c_InstanceID))
  58. {
  59. callManager.Add(c_InstanceID, new AnimatorCallElement(animator));
  60. }
  61. CheckEvent(animator, c_InstanceID);
  62. callManager[c_InstanceID].onOverByStateNameHash -= call;
  63. callManager[c_InstanceID].onOverByStateNameHash += call;
  64. }
  65. /// <summary>
  66. /// 移除一个监听
  67. /// </summary>
  68. /// <param name="animator"></param>
  69. /// <param name="call"></param>
  70. public void RemoveListener(Animator animator, System.Action<int,int> call)
  71. {
  72. string c_InstanceID = animator.gameObject.GetInstanceID() + "";
  73. if (callManager.ContainsKey(c_InstanceID))
  74. {
  75. callManager[c_InstanceID].onOverByStateNameHash -= call;
  76. }
  77. }
  78. AnimationClip[] c_clips;
  79. AnimationEvent[] c_events;
  80. /// <summary>
  81. /// 检查是否有Event
  82. /// </summary>
  83. /// <param name="animator"></param>
  84. /// <param name="c_InstanceID"></param>
  85. private void CheckEvent(Animator animator,string c_InstanceID)
  86. {
  87. if (animator.GetComponent<AnimatorOverCall>() == null)
  88. {
  89. AnimatorOverCall animatorOverCall = animator.gameObject.AddComponent<AnimatorOverCall>();
  90. animatorOverCall.SetInstanceID(c_InstanceID);
  91. c_clips = animator.runtimeAnimatorController.animationClips;
  92. for (int i = 0,length = c_clips.Length; i < length; i++)
  93. {
  94. if (c_clips[i] == null)
  95. {
  96. continue;
  97. }
  98. c_events = c_clips[i].events;
  99. for (int j = 0; j < c_events.Length; j++)
  100. {
  101. if (c_events[j] == null)
  102. {
  103. continue;
  104. }
  105. if (c_events[j].functionName == "OverCall")
  106. {
  107. return;
  108. }
  109. }
  110. c_clips[i].AddEvent(new AnimationEvent() { functionName = "OverCall", time = c_clips[i].length });
  111. }
  112. }
  113. }
  114. #region 内部类
  115. private class AnimatorCallElement
  116. {
  117. public AnimatorCallElement(Animator animator)
  118. {
  119. this.animator = animator;
  120. }
  121. private Animator animator;
  122. internal System.Action onOver;
  123. internal event System.Action<int, int> onOverByStateNameHash;
  124. internal void DoOver()
  125. {
  126. if (onOverByStateNameHash != null)
  127. {
  128. for (int i = 0, length = animator.layerCount; i < length; i++)
  129. {
  130. onOverByStateNameHash.Invoke(i, animator.GetCurrentAnimatorStateInfo(i).shortNameHash);
  131. }
  132. }
  133. onOver?.Invoke();
  134. onOver = null;
  135. }
  136. }
  137. #endregion
  138. }
  139. /// <summary>
  140. /// 对Animator扩展
  141. /// </summary>
  142. public static class AnimatorExtend
  143. {
  144. public static void Play(this Animator animator, string name, System.Action action,int layout=0)
  145. {
  146. if (animator.HasState(layout, Animator.StringToHash(name)))
  147. {
  148. animator.Play(name, layout);
  149. AnimatorOverCallMgr.I.AddListener(animator, action);
  150. }
  151. else
  152. {
  153. action?.Invoke();
  154. Debug.LogError("没有:" + name+"State");
  155. }
  156. }
  157. /// <summary>
  158. /// 添加完毕监听
  159. /// </summary>
  160. /// <param name="animater"></param>
  161. /// <param name="action">返回值是(Layer,StateNameHash)</param>
  162. public static void AddOverCall(this Animator animater, System.Action<int, int> action)
  163. {
  164. AnimatorOverCallMgr.I.AddListener(animater, action);
  165. }
  166. /// <summary>
  167. /// 移除完毕监听
  168. /// </summary>
  169. /// <param name="animater"></param>
  170. /// <param name="action"></param>
  171. public static void RemoveOverCall(this Animator animater, System.Action<int,int> action)
  172. {
  173. AnimatorOverCallMgr.I.RemoveListener(animater, action);
  174. }
  175. }
  176. [DisallowMultipleComponent]
  177. internal class AnimatorOverCall : MonoBehaviour
  178. {
  179. private string instanceID;
  180. internal void SetInstanceID(string id)
  181. {
  182. instanceID = id;
  183. }
  184. public void OverCall()
  185. {
  186. AnimatorOverCallMgr.I.HandleEvent(instanceID);
  187. }
  188. private void OnDestroy()
  189. {
  190. AnimatorOverCallMgr.I.RemoveHandleEvent(instanceID);
  191. }
  192. }
  193. }

更复杂的可以考虑StateMachineBehaviour!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/114666
推荐阅读
相关标签
  

闽ICP备14008679号