unity中绑定动画的行为系统

news2024/11/18 13:41:48

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


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

使用示例

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


 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1065125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据科学最佳实践:Kedro 的工程化解决方案 | 开源日报 No.47

leonardomso/33-js-concepts Stars: 58.4k License: MIT 这个项目是一个帮助开发者掌握 JavaScript 概念的资源库。该项目基于 Stephen Curtis 撰写的一篇文章&#xff0c;包含了对 33 个重要 JavaScript 概念全面深入地讲解&#xff0c;并被 GitHub 评为 2018 年最佳开源项目…

Python Random模块详解

Random模块详解 随机数 random模块 randint(a, b) 返回[a, b]之间的整数randrange ([start,] stop [,step]) 从指定范围内&#xff0c;按指定基数递增的集合中获取一个随机数&#xff0c;基数 缺省值为1。random.randrange(1,7,2)choice(seq) 从非空序列的元素中随机挑选一个…

驱动器类产品的接口EMC拓扑方案

驱动器类产品的接口EMC拓扑方案 1. 概述 本文以高压伺服驱动器和变频器类产品为例&#xff0c;对常用端口滤波拓扑方案进行总结&#xff0c;后续根据不同的应用场景可进行适当删减&#xff0c;希望对大家有帮助。 2. 驱动器验证等级 本文推荐拓扑的实验结果&#xff0c;满足…

Ps:选择并遮住

选择并遮住 Select and Mask主要用来提高选区边缘的品质&#xff0c;尤其在毛发等复杂边缘的抠图上发挥强大的作用。 Ps菜单&#xff1a;选择/选择并遮住 Select and Mask 快捷键&#xff1a;Ctrl Alt R 在所有选区工具的工具选项栏上以及图层蒙版的属性面板中都可以看到“选…

NAT+ACL+mstp小综合

三、实验一相关知识点 1&#xff0c;实验&#xff1a;NAT 综合实验 2&#xff0c;拓扑&#xff1a; 3&#xff0c;需求: 1&#xff09;&#xff0c;实现VLAN20 的除了20这台主机以外所有主机上网访问外网 2&#xff09;&#xff0c;实现VLAN30 的主机为奇数电脑上网 3&#…

详解C语言—预处理

目录 1、预处理 (1)预定义符号介绍 (2)预处理指令 #define #define 定义标识符&#xff1a; #define 定义宏&#xff1a; #define 替换规则 (3)预处理操作符# (4)预处理操作符## (5)带副作用的宏参数 (6)宏和函数对比 2、命名约定 3、预处理指令 #undef 4、命令行定…

用 Pytorch 自己构建一个Transformer

一、说明 用pytorch自己构建一个transformer并不是难事,本篇使用pytorch随机生成五千个32位数的词向量做为源语言词表,再生成五千个32位数的词向量做为目标语言词表,让它们模拟翻译过程,transformer全部用pytorch实现,具备一定实战意义。 二、论文和概要 …

mac连接easyconnnect显示“本地环境出现异常”

mac连接easyconnnect显示“本地环境出现异常” 解决方法&#xff1a; 终端下输入&#xff1a;vim ~/.zprofile文件内加入如下内容&#xff0c;如下图&#xff1a; ####解决连接easyconnnect显示“本地环境出现异常问题 function EC_start(){/Applications/EasyConnect.app/Co…

学信息系统项目管理师第4版系列19_质量管理

1. 公差 1.1. 质量测量中公差是测量指标的可允许变动范围&#xff0c;而不是实际测量值与预期值的差 1.1.1. 【高22下选35】 1.2. 结果的的可接受范围 2. 控制界限 2.1. 统计意义上稳定的过程或过程绩效的普通偏差的边界 3. 3版 3.1. 质量控制新七工具 3.1.1. 【高19下…

cpp primer笔记070-算法函数

accumulate的第三个参数的类型决定了函数中使用哪个加法运算符以及返回值的类型&#xff0c;如果返回值是自定义类型&#xff0c;需要使用accumlate&#xff0c;则需要重载运算符&#xff0c;该接口的第三个参数返回的是一个需要处理的数据类型的一个变量。 std::vector<std…

蓝桥等考Python组别十四级001

第一部分&#xff1a;选择题 1、Python L14 &#xff08;15分&#xff09; 运行下面程序&#xff0c;输出的结果是&#xff08; &#xff09;。 d {A: 501, B: 602, C: 703, D: 804} print(d[B]) 501602703804 正确答案&#xff1a;B 2、Python L14 &#xff08;15分…

吃鸡高手必备工具大揭秘!提高战斗力,分享干货,一站满足!

大家好&#xff01;你是否想提高吃鸡游戏的战斗力&#xff0c;分享顶级的游戏作战干货&#xff0c;方便进行吃鸡作图和查询装备皮肤库存&#xff1f;是否也担心被骗&#xff0c;希望查询游戏账号是否在黑名单上&#xff0c;或者查询失信人和VAC封禁情况&#xff1f;在这段视频中…

System Generator学习——使用 AXI 接口和 IP 集成器

文章目录 前言一、目标二、步骤1、检查 AXI 接口2、使用 System Generator IP 创建一个 Vivado 项目3、创建 IP 集成设计&#xff08;IPI&#xff09;4、实现设计 总结 前言 在本节中&#xff0c;将学习如何使用 System Generator 实现 AXI 接口。将以 IP 目录格式保存设计&am…

「专题速递」回声消除算法、低功耗音频、座舱音频系统、智能音频技术、低延时音效算法、手机外放增强算法...

随着多媒体和通信网络技术的持续升级&#xff0c;以及新型音视频应用场景的不断涌现&#xff0c;音频处理技术正朝着更加智能化和沉浸化的方向迅猛发展。人们对音频听觉体验的要求也逐渐提高&#xff0c;无论是在何种场景下&#xff0c;都期望获得更加清晰的声音&#xff0c;并…

吃鸡高手必备!这些技巧帮你提高战斗力!

大家好&#xff01;作为一名吃鸡玩家&#xff0c;我们都想提高自己的战斗力&#xff0c;享受顶级游戏作战干货&#xff0c;装备皮肤库存展示和查询&#xff0c;并避免被骗游戏账号。在这里&#xff0c;我将为大家介绍一些实用的技巧和工具&#xff0c;让你成为吃鸡高手&#xf…

三相逆变器下垂控制双机

下垂控制的原理推荐看这篇知乎&#xff08;形象又生动&#xff09;&#xff1a;https://www.zhihu.com/question/41003509/answer/518837491 主拓扑图 控制主要模块 Droop子模块 监控有功结果 1、从两台逆变器输出的有功功率波形可以看到&#xff0c;在负载突变的时候&#xf…

卷积网络的发展历史-AlexNet

简介 2012 年&#xff0c;Krizhevsky 与 Hinton 推出了 AlexNet&#xff0c;引起了许多学者对深度学习的研究&#xff0c;可以算是深度学习的热潮的起始标志。在图像分类领域不得不提的就是ImageNet大规模视觉挑战赛(ILSVRC)&#xff0c;它被称为深度学习在图像分类任务研究方…

《Spring框架原理》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

杂记 define,typedef,static,memset,ifndef,递归,逻辑与,整型提升,算术转换

目录 常量&#xff0c;define typedef static ​编辑​编辑 #define定义常量和宏 指针 ​编辑 操作系统&#xff0c;网络 system执行系统命令 memset ifndef 递归 冒泡排序 单目操作符 逻辑与&& 隐式类型转换 整型提升 算术转换 有符号无符号所占的…

网络架构中PHY芯片可否不使用网络变压器/网络隔离变压器连接呢?

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;常有人询问网络架构中&#xff0c;PHY芯片通常使用的网络变压器&#xff08;也叫网络隔离变压器&#xff09;可否节省不用&#xff0c;以降低成本&#xff0c;今天就相关问题做个探讨&#xff1b; 一 &#xff0c;P…