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


 
}
相关推荐
异次元的归来10 小时前
Unity DOTS中的share component
unity·游戏引擎
向宇it13 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
_oP_i14 小时前
unity webgl部署到iis报错
unity
Go_Accepted14 小时前
Unity全局雾效
unity
向宇it14 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
每日出拳老爷子17 小时前
【图形渲染】【Unity Shader】【Nvidia CG】有用的参考资料链接
unity·游戏引擎·图形渲染
北海651618 小时前
Dots 常用操作
unity
YY-nb1 天前
Unity Apple Vision Pro 开发教程:物体识别跟踪
unity·游戏引擎·apple vision pro
Cool-浩1 天前
Unity 开发Apple Vision Pro物体识别追踪ObjectTracking
unity·ar·apple vision pro·mr·物体识别·vision pro教程·objecttracking
向宇it2 天前
【从零开始入门unity游戏开发之——C#篇23】C#面向对象继承——`as`类型转化和`is`类型检查、向上转型和向下转型、里氏替换原则(LSP)
java·开发语言·unity·c#·游戏引擎·里氏替换原则