unity中绑定动画的行为系统

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

cs 复制代码
public class Enemy : MonoBehaviour
{
      
    
        public event Action E_AnimatorFin;//当动画播放完毕时

        public Action DefaultAction;//默认事件
     
        public Dictionary<Action, string> EventAnimator= new();//Event对应的动画
        public List<Action> Eventlist=new();//要做的event列表

        private Animator ani;
        
        
        public virtual void Start()
        {
              
                ani = GetComponent<Animator>();
                E_AnimatorFin += OnAnimatorFinish;
             
                StartCoroutine(SpawningAnimator());
                IEnumerator SpawningAnimator()
                {
                        yield return new WaitForSeconds(0.02f);
                        PlayAnimator(ani, EventAnimator[ Eventlist[0]],
                                () =>
                                {
                                        Debug.Log("动画播放前执行代码"+ EventAnimator[ Eventlist[0]]);
                                },
                                () =>
                                {
                                        E_AnimatorFin?.Invoke();
                                        Debug.Log("动画播放完执行代码");
                                });
                }

        }



        public virtual void OnAnimatorFinish()
        {
                StartCoroutine(spawnanimator());
                IEnumerator spawnanimator()
                {
                      
                        yield return new WaitForSeconds(0.02f);
                        if (Eventlist.Count == 0)
                                {
                                        Eventlist.Add(DefaultAction);
                                        Debug.LogWarning(name+$"并没有新的事件,目前在执行默认的事件");
                                }
                           
                          
                                
                        try
                        {
                                PlayAnimator(ani, EventAnimator[ Eventlist[0]],
                                        () =>
                                        {
                                                Debug.LogError($"执行前{EventAnimator[ Eventlist[0]]}");
                                                Eventlist[0]();
                                        },
                                        () =>
                                        {
                                                Debug.LogError("执行完");
                                                E_AnimatorFin?.Invoke();
                                        }); 
                        }
                        catch (KeyNotFoundException e)
                        {
                               Debug.LogError(Eventlist[0].Method.Name+"没有匹配动画!");
                        }
                        Eventlist.RemoveAt(0);
                }
               
        }

        

        #region Animator
        public void PlayAnimator(Animator animator, string clipName, Action startAct = null, Action endAct = null)
        {
                StartCoroutine(PlayAnimationItor(animator, clipName, startAct, endAct));
        }

        /// <summary>
        /// Animation动画播放迭代器
        /// </summary>
        /// <param name="animation">Animation组件</param>
        /// <param name="clipName">clip片段名</param>
        /// <param name="startAct">委托函数</param>
        /// <param name="endAct">委托函数</param>
        /// <returns></returns>
        private IEnumerator PlayAnimationItor(Animator animator, string clipName, Action startAct=null, Action endAct=null)
        {
                startAct?.Invoke();
                animator.Play(clipName);
                // 获取目标动画的名称
                string targetClipName =clipName;
                yield return StartCoroutine(WaitForEndOfAnimr(targetClipName));
                IEnumerator WaitForEndOfAnimr(string targetName)
                {
                        yield return new WaitForSeconds(0.1f);//为过渡动画预留时间
                        AnimatorClipInfo[] clipInfo = animator.GetCurrentAnimatorClipInfo(0);
                        Debug.Log("Targetname>>"+targetName);
                        while (animator.GetCurrentAnimatorStateInfo(0).IsName(targetName))
                        {
                                // 获取当前动画片段信息
                                clipInfo = animator.GetCurrentAnimatorClipInfo(0);
                                if (clipInfo.Length > 0)
                                {
                                        // 获取当前播放的动画片段的名称
                                        string currentClipName = clipInfo[0].clip.name;
                                        Debug.Log("当前播放的动画片段名称: " + currentClipName);
                                }

                                yield return new WaitForSeconds(0.01f);
                        }
                }
//                Debug.LogError($"{animator.GetCurrentAnimatorClipInfo(0)[0].clip.name}+{targetClipName}");
                endAct?.Invoke();
        }
        


#endregion

        #region  AI逻辑

        /// <summary>
        /// 设置没有事件列表时自动执行的事件
        /// </summary>
        /// <param name="t"></param>
        public void SetDefaultEvent(Action t)
        {
                DefaultAction = t;
        }
        /// <summary>
        /// 为怪物添加一个事件到列表
        /// </summary>
        /// <param name="action"></param>
        public void AddEvent(Action action)
        {
                Eventlist.Add(action);
        }

        /// <summary>
        /// 重置怪物事件列表为一个新的列表
        /// </summary>
        /// <param name="actions"></param>
        public void SetEvent(Action[] actions)
        {
                foreach (var VARIABLE in Eventlist)
                {
                        Eventlist.Remove(VARIABLE);
                }

                foreach (var VARIABLE in actions)
                {
                        Eventlist.Add(VARIABLE);
                }
        }
        
        /// <summary>
        /// 强制加入一个事件到下一个行动
        /// </summary>
        /// <param name="add">增加的事件</param>
        public void NextEvent(Action addAction)
        {
                Debug.Log("length="+Eventlist.Count);
                if (Eventlist.Count>0)
                {
                        Eventlist.Insert(1,addAction);
                }
                else
                {
                        Eventlist.Add(addAction);
                }

        }

        /// <summary>
        /// 强制指定下一个事件且立刻执行
        /// </summary>
        /// <param name="addAction"></param>
        public void DoNextEvent(Action addAction)
        {
                StopAllCoroutines();
                NextEvent(addAction);
                if (Eventlist.Count>1)
                {
                        Eventlist.RemoveAt(0);
                }
             
              
                        PlayAnimator(ani, EventAnimator[ Eventlist[0]],
                                () =>
                                {
                                        Eventlist[0]();
                                        Debug.Log("动画播放前执行代码"+ EventAnimator[ Eventlist[0]]);
                                },
                                () =>
                                {
                                        E_AnimatorFin?.Invoke();
                                        Debug.Log("动画播放完执行代码");
                                });
                

        }
        
#endregion

使用示例

cs 复制代码
public class Cow : Enemy
{
    private GameObject normalATK;
    public  void Awake()
    {
        normalATK = transform.Find("NormalATK").gameObject;
        normalATK.SetActive(false);
        
       EventAnimator.Add(AI_DoRandomRelex,"Start");//为事件指定对应动画
      EventAnimator.Add(Animator_Idle,"idle");
      EventAnimator.Add(Animator_Rest,"rest");
      EventAnimator.Add(AI_FindPlayer,"walk");
      EventAnimator.Add(AI_Attack,"attack");
      SetDefaultEvent(AI_DoRandomRelex);//设置默认动画
      AddEvent(DefaultAction);//添加默认动画

      E_HPChanged += () => {Debug.LogError("收到伤害"); };
      E_HPChanged += ToHostile;//收到伤害时敌对
   }

    /// <summary>
    /// 收到伤害的时候调用,改为攻击模式
    /// </summary>
    void ToHostile()
    {
        DoNextEvent(AI_FindPlayer);
        SetDefaultEvent(AI_FindPlayer);
        FriendlyTag = FriendlyLevel.Hostile;
      
    }
    public void AI_DoRandomRelex()//中立状态时随机做待机动画
    {
        int rd = Random.Range(0, 100);
        if (rd<51)
        {
            Debug.Log("next>>idle");
            NextEvent(Animator_Idle);
        }
        else
        {
            Debug.Log("next>>rest");
            NextEvent(Animator_Rest);
        }
    }
   private void Animator_Idle()//待机动画只有动画效果,没有要执行的内容
   {
      Debug.Log("IDLE");
   }
   
   private void Animator_Rest()
   {
       Debug.Log("REST");
   }
   private void Debug3()
   {
       
   }

   bool finder;//只有在事件进行的时候才追踪.当事件结束后退出追踪循环
   public override void AI_FindPlayer()//在敌对状态默认追踪玩家
   {

       finder = true;
       StartCoroutine(basefind());

       E_AnimatorFin += setfinder;
       IEnumerator basefind()
       {
           while (finder)
           {
               base.AI_FindPlayer();
               yield return new WaitForSeconds(0.1f);
           }

           E_AnimatorFin -= setfinder;
       }
       void setfinder()
       {
           finder = false;
       }

       StartCoroutine(atrange());
       E_AnimatorFin += () => { StopCoroutine(atrange()); };
       IEnumerator atrange()
       {
           do
           {
               if (IsPlayerInAttackRange)//如果玩家在攻击范围内就进行攻击事件
               {
                   DoNextEvent(AI_Attack);
               }
               yield return new WaitForSeconds(0.02f);
           } while (true);
       }

   }

   public void AI_Attack()//攻击事件
   {
       base.AI_FindPlayer();
       Debug.LogError("AIATK");
       StartCoroutine(WaitATK());
       E_AnimatorFin += () => {des();  };
       IEnumerator WaitATK()
       {
           yield return new WaitForSeconds(0.2f * EventSpeed);
           normalATK.SetActive(true);
       } 
       void des()
       {
           normalATK.SetActive(false);
           E_AnimatorFin -= des;
       }
   }

   public override void Update()
   {
       base.Update();

//如果玩家在索敌范围外就变回中立
       if (!IsPlayerInFindingRange&& (FriendlyTag == FriendlyLevel.Hostile))
       {
           FriendlyTag = FriendlyLevel.Neutral;
           SetDefaultEvent(AI_DoRandomRelex);
       }
   }


 
}
相关推荐
牙膏上的小苏打233315 小时前
Unity Surround开关后导致获取主显示器分辨率错误
unity·主屏幕
Unity大海17 小时前
诠视科技Unity SDK开发环境配置、项目设置、apk打包。
科技·unity·游戏引擎
浅陌sss1 天前
Unity中 粒子系统使用整理(一)
unity·游戏引擎
维度攻城狮1 天前
实现在Unity3D中仿真汽车,而且还能使用ros2控制
python·unity·docker·汽车·ros2·rviz2
为你写首诗ge1 天前
【Unity网络编程知识】FTP学习
网络·unity
神码编程1 天前
【Unity】 HTFramework框架(六十四)SaveDataRuntime运行时保存组件参数、预制体
unity·编辑器·游戏引擎
菲fay1 天前
Unity 单例模式写法
unity·单例模式
火一线1 天前
【Framework-Client系列】UIGenerate介绍
游戏·unity
ZKY_241 天前
【工具】Json在线解析工具
unity·json
ZKY_242 天前
【Unity】处理文字显示不全的问题
unity·游戏引擎