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);
       }
   }


 
}
相关推荐
游乐码12 小时前
UnityGUI(五)GUI控件综合使用
开发语言·unity·c#
LF男男12 小时前
TshitBullect.cs
unity
游乐码20 小时前
Unity(十六)切换场景及鼠标相关
unity·游戏引擎
FakeEnd21 小时前
Unity开发笔记6
笔记·unity·游戏引擎
游乐码21 小时前
Unity(十七)Unity随机数及Unity委托
unity·游戏引擎
ellis197021 小时前
Unity性能优化之检测工具Profiler
unity·性能优化
RPGMZ1 天前
RPGMZ游戏引擎 一个窗口 文本居中显示
开发语言·javascript·游戏引擎·rpgmz
tohand1 天前
Unity 完美假阴影实现文档
unity·游戏引擎
@蓝莓果粒茶1 天前
【Unity笔记】保姆级AssetBundle详解(含代码+避坑指南)
笔记·游戏·unity
Zephyr_01 天前
Unity2D游戏制作
游戏·unity