• unity中绑定动画的行为系统


    主要代码逻辑是创建一个action队列,当动画播放结束时就移除队头,执行后面的事件

    1. public class Enemy : MonoBehaviour
    2. {
    3. public event Action E_AnimatorFin;//当动画播放完毕时
    4. public Action DefaultAction;//默认事件
    5. public Dictionarystring> EventAnimator= new();//Event对应的动画
    6. public List Eventlist=new();//要做的event列表
    7. private Animator ani;
    8. public virtual void Start()
    9. {
    10. ani = GetComponent();
    11. E_AnimatorFin += OnAnimatorFinish;
    12. StartCoroutine(SpawningAnimator());
    13. IEnumerator SpawningAnimator()
    14. {
    15. yield return new WaitForSeconds(0.02f);
    16. PlayAnimator(ani, EventAnimator[ Eventlist[0]],
    17. () =>
    18. {
    19. Debug.Log("动画播放前执行代码"+ EventAnimator[ Eventlist[0]]);
    20. },
    21. () =>
    22. {
    23. E_AnimatorFin?.Invoke();
    24. Debug.Log("动画播放完执行代码");
    25. });
    26. }
    27. }
    28. public virtual void OnAnimatorFinish()
    29. {
    30. StartCoroutine(spawnanimator());
    31. IEnumerator spawnanimator()
    32. {
    33. yield return new WaitForSeconds(0.02f);
    34. if (Eventlist.Count == 0)
    35. {
    36. Eventlist.Add(DefaultAction);
    37. Debug.LogWarning(name+$"并没有新的事件,目前在执行默认的事件");
    38. }
    39. try
    40. {
    41. PlayAnimator(ani, EventAnimator[ Eventlist[0]],
    42. () =>
    43. {
    44. Debug.LogError($"执行前{EventAnimator[ Eventlist[0]]}");
    45. Eventlist[0]();
    46. },
    47. () =>
    48. {
    49. Debug.LogError("执行完");
    50. E_AnimatorFin?.Invoke();
    51. });
    52. }
    53. catch (KeyNotFoundException e)
    54. {
    55. Debug.LogError(Eventlist[0].Method.Name+"没有匹配动画!");
    56. }
    57. Eventlist.RemoveAt(0);
    58. }
    59. }
    60. #region Animator
    61. public void PlayAnimator(Animator animator, string clipName, Action startAct = null, Action endAct = null)
    62. {
    63. StartCoroutine(PlayAnimationItor(animator, clipName, startAct, endAct));
    64. }
    65. ///
    66. /// Animation动画播放迭代器
    67. ///
    68. /// Animation组件
    69. /// clip片段名
    70. /// 委托函数
    71. /// 委托函数
    72. ///
    73. private IEnumerator PlayAnimationItor(Animator animator, string clipName, Action startAct=null, Action endAct=null)
    74. {
    75. startAct?.Invoke();
    76. animator.Play(clipName);
    77. // 获取目标动画的名称
    78. string targetClipName =clipName;
    79. yield return StartCoroutine(WaitForEndOfAnimr(targetClipName));
    80. IEnumerator WaitForEndOfAnimr(string targetName)
    81. {
    82. yield return new WaitForSeconds(0.1f);//为过渡动画预留时间
    83. AnimatorClipInfo[] clipInfo = animator.GetCurrentAnimatorClipInfo(0);
    84. Debug.Log("Targetname>>"+targetName);
    85. while (animator.GetCurrentAnimatorStateInfo(0).IsName(targetName))
    86. {
    87. // 获取当前动画片段信息
    88. clipInfo = animator.GetCurrentAnimatorClipInfo(0);
    89. if (clipInfo.Length > 0)
    90. {
    91. // 获取当前播放的动画片段的名称
    92. string currentClipName = clipInfo[0].clip.name;
    93. Debug.Log("当前播放的动画片段名称: " + currentClipName);
    94. }
    95. yield return new WaitForSeconds(0.01f);
    96. }
    97. }
    98. // Debug.LogError($"{animator.GetCurrentAnimatorClipInfo(0)[0].clip.name}+{targetClipName}");
    99. endAct?.Invoke();
    100. }
    101. #endregion
    102. #region AI逻辑
    103. ///
    104. /// 设置没有事件列表时自动执行的事件
    105. ///
    106. ///
    107. public void SetDefaultEvent(Action t)
    108. {
    109. DefaultAction = t;
    110. }
    111. ///
    112. /// 为怪物添加一个事件到列表
    113. ///
    114. ///
    115. public void AddEvent(Action action)
    116. {
    117. Eventlist.Add(action);
    118. }
    119. ///
    120. /// 重置怪物事件列表为一个新的列表
    121. ///
    122. ///
    123. public void SetEvent(Action[] actions)
    124. {
    125. foreach (var VARIABLE in Eventlist)
    126. {
    127. Eventlist.Remove(VARIABLE);
    128. }
    129. foreach (var VARIABLE in actions)
    130. {
    131. Eventlist.Add(VARIABLE);
    132. }
    133. }
    134. ///
    135. /// 强制加入一个事件到下一个行动
    136. ///
    137. /// 增加的事件
    138. public void NextEvent(Action addAction)
    139. {
    140. Debug.Log("length="+Eventlist.Count);
    141. if (Eventlist.Count>0)
    142. {
    143. Eventlist.Insert(1,addAction);
    144. }
    145. else
    146. {
    147. Eventlist.Add(addAction);
    148. }
    149. }
    150. ///
    151. /// 强制指定下一个事件且立刻执行
    152. ///
    153. ///
    154. public void DoNextEvent(Action addAction)
    155. {
    156. StopAllCoroutines();
    157. NextEvent(addAction);
    158. if (Eventlist.Count>1)
    159. {
    160. Eventlist.RemoveAt(0);
    161. }
    162. PlayAnimator(ani, EventAnimator[ Eventlist[0]],
    163. () =>
    164. {
    165. Eventlist[0]();
    166. Debug.Log("动画播放前执行代码"+ EventAnimator[ Eventlist[0]]);
    167. },
    168. () =>
    169. {
    170. E_AnimatorFin?.Invoke();
    171. Debug.Log("动画播放完执行代码");
    172. });
    173. }
    174. #endregion

    使用示例

    1. public class Cow : Enemy
    2. {
    3. private GameObject normalATK;
    4. public void Awake()
    5. {
    6. normalATK = transform.Find("NormalATK").gameObject;
    7. normalATK.SetActive(false);
    8. EventAnimator.Add(AI_DoRandomRelex,"Start");//为事件指定对应动画
    9. EventAnimator.Add(Animator_Idle,"idle");
    10. EventAnimator.Add(Animator_Rest,"rest");
    11. EventAnimator.Add(AI_FindPlayer,"walk");
    12. EventAnimator.Add(AI_Attack,"attack");
    13. SetDefaultEvent(AI_DoRandomRelex);//设置默认动画
    14. AddEvent(DefaultAction);//添加默认动画
    15. E_HPChanged += () => {Debug.LogError("收到伤害"); };
    16. E_HPChanged += ToHostile;//收到伤害时敌对
    17. }
    18. ///
    19. /// 收到伤害的时候调用,改为攻击模式
    20. ///
    21. void ToHostile()
    22. {
    23. DoNextEvent(AI_FindPlayer);
    24. SetDefaultEvent(AI_FindPlayer);
    25. FriendlyTag = FriendlyLevel.Hostile;
    26. }
    27. public void AI_DoRandomRelex()//中立状态时随机做待机动画
    28. {
    29. int rd = Random.Range(0, 100);
    30. if (rd<51)
    31. {
    32. Debug.Log("next>>idle");
    33. NextEvent(Animator_Idle);
    34. }
    35. else
    36. {
    37. Debug.Log("next>>rest");
    38. NextEvent(Animator_Rest);
    39. }
    40. }
    41. private void Animator_Idle()//待机动画只有动画效果,没有要执行的内容
    42. {
    43. Debug.Log("IDLE");
    44. }
    45. private void Animator_Rest()
    46. {
    47. Debug.Log("REST");
    48. }
    49. private void Debug3()
    50. {
    51. }
    52. bool finder;//只有在事件进行的时候才追踪.当事件结束后退出追踪循环
    53. public override void AI_FindPlayer()//在敌对状态默认追踪玩家
    54. {
    55. finder = true;
    56. StartCoroutine(basefind());
    57. E_AnimatorFin += setfinder;
    58. IEnumerator basefind()
    59. {
    60. while (finder)
    61. {
    62. base.AI_FindPlayer();
    63. yield return new WaitForSeconds(0.1f);
    64. }
    65. E_AnimatorFin -= setfinder;
    66. }
    67. void setfinder()
    68. {
    69. finder = false;
    70. }
    71. StartCoroutine(atrange());
    72. E_AnimatorFin += () => { StopCoroutine(atrange()); };
    73. IEnumerator atrange()
    74. {
    75. do
    76. {
    77. if (IsPlayerInAttackRange)//如果玩家在攻击范围内就进行攻击事件
    78. {
    79. DoNextEvent(AI_Attack);
    80. }
    81. yield return new WaitForSeconds(0.02f);
    82. } while (true);
    83. }
    84. }
    85. public void AI_Attack()//攻击事件
    86. {
    87. base.AI_FindPlayer();
    88. Debug.LogError("AIATK");
    89. StartCoroutine(WaitATK());
    90. E_AnimatorFin += () => {des(); };
    91. IEnumerator WaitATK()
    92. {
    93. yield return new WaitForSeconds(0.2f * EventSpeed);
    94. normalATK.SetActive(true);
    95. }
    96. void des()
    97. {
    98. normalATK.SetActive(false);
    99. E_AnimatorFin -= des;
    100. }
    101. }
    102. public override void Update()
    103. {
    104. base.Update();
    105. //如果玩家在索敌范围外就变回中立
    106. if (!IsPlayerInFindingRange&& (FriendlyTag == FriendlyLevel.Hostile))
    107. {
    108. FriendlyTag = FriendlyLevel.Neutral;
    109. SetDefaultEvent(AI_DoRandomRelex);
    110. }
    111. }
    112. }

  • 相关阅读:
    基于springboot实现校园交友网站管理系统项目【项目源码+论文说明】
    MySQL数据库——索引(6)-索引使用(覆盖索引与回表查询,前缀索引,单列索引与联合索引 )、索引设计原则、索引总结
    每天一个注解之@RestController
    Jenkins pipline集成发布到K8s
    C++openCV在QT中图像的显示(mat格式照片和Qimage格式互转)
    提高爬虫效率的秘诀之一:合理配置库池数量
    Linguistic Steganalysis in Few-Shot Scenario论文阅读笔记
    你用过哪些设计模式(一)?
    1.实验技术-收藏吃灰去,深入浅出常规PCR
    Go 语言基础语法 3
  • 原文地址:https://blog.csdn.net/qq_58804985/article/details/133631268