unity中绑定动画的行为系统

主要代码逻辑是创建一个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 Animatorpublic 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.hqwc.cn/news/128724.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AndroidStudio添加一个虚拟设备

虚拟设备管理器 这个是AndroidStudio的启动界面 虚拟设备管理界面 点击加号&#xff0c;新增 选择手机型号 选择系统版本 虚拟设备名 完成

PHP 伪协议:使用 php://filter 为数据流应用过滤器

文章目录 参考环境PHP 伪协议概念为什么需要 PHP 伪协议&#xff1f; php://filter概念格式 基本使用普通读写file_get_contents 与 file_put_contentsinclude 过滤器的基本使用base64 的编码与解码rot13 加解密rot13 算法string.rot13 过滤器列表多个过滤器的使用注意事项 处理…

手摸手系列之批量修改MySQL数据库所有表中某些字段的类型

在迁移老项目的数据库时&#xff0c;使用Navicat Premium的数据传输功能同步了表结构和数据。但是&#xff0c;发现某些字段的数据类型出现了错误&#xff0c;例如&#xff0c;租户ID从Oracle的NUMBER类型变成了MySQL的decimal(10)&#xff0c;正确的应该是bigInt(20)。此外&am…

voc数据集格式与yolo数据集格式的区别及相互转化

Pascal VOC数据集是目标检测领域最常用的标准数据集之一&#xff0c;几乎所有检测方向的论文都会给出其在VOC数据集上训练并评测的效果。VOC数据集包含的信息非常全&#xff0c;它不仅被拿来做目标检测&#xff0c;也可以拿来做分割等任务&#xff0c;因此除了目标检测所需的文…

kafka与zookeeper的集群

基础配置 systemctl stop firewalld && systemctl disable firewalld setenforce 0 sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/configvi /etc/hosts ip1 node1 ip2 node2 ip3 node3zookeeper介绍 zookeeper是一个分布式的协调服务&#xff0c;主要用…

【window10】Dart+Android Studio+Flutter安装及运行

安装Dart SDK安装Android Studio安装Flutter在Android Studio中创建并运行Flutter项目 安装前&#xff0c;请配置好你的jdk环境&#xff0c;准备好你的梯子~ 安装Dart SDK 浅浅了解一下Dart&#xff1a; Dart 诞生于2011年&#xff0c;是由谷歌开发的一种强类型、跨平台的客户…

【计算机视觉 05】YOLO论文讲解:V1-V7

https://ai.deepshare.net/live_pc/l_63243a65e4b050af23b79338 Part1.目标检测与YOLO系列 1. 目标检测任务及发展脉络 2. YOLO的发展史 Anchors Base原理&#xff1a; Part2.YOLOV1-V3 3. YOLO V1的网络结构 4. YOLO V3的网络结构与实验结果 Part3.YOLO的进化 5. YOLO V4的网络…

每个前端都要学的【前端自动化部署】,Devops,CI/CD

原文发布于&#xff1a;2023-09-21 11:50 作者&#xff1a;65岁退休Coder 原文链接&#xff1a;https://juejin.cn/post/7102360505313918983 DevOps 当我们提到 Jenkins&#xff0c;大家首先想到的概念就是 CI/CD&#xff0c;在这之前我们应该再了解一个概念。 DevOps&#…

轻松实现时间录入自由!如何在Microsoft Word中轻松插入格式化的日期和时间

在文档中插入当前日期和时间有几个原因。你可能希望将其插入信函或页眉或页脚中。无论是什么原因&#xff0c;Word都可以轻松地将日期和时间插入文档。 如果希望在打开或打印文档时自动更新日期和时间&#xff0c;可以将其作为自动更新的字段插入。该字段也可以随时手动更新。…

六个交易日市值蒸发20亿港元,第四范式难逃AI大模型“魔咒”

AI独角兽第四范式终于敲钟了。 北京第四范式智能技术股份有限公司(06682.HK&#xff0c;下称“第四范式”)于9月28日正式挂牌港交所&#xff0c;发行价为55.60港元/股&#xff0c;IPO首日报收58.50港元/股。 上市后6个交易日&#xff0c;截至10月6日港股收盘&#xff0c;第四…

一文读懂Base64

这几天在和第三方交互的时候&#xff0c;对方返回的数据是base64格式的数据&#xff0c;所以这两天又彻底捋了下Base64的来龙去脉。之前看过一篇文章说的非常好&#xff08;再找到给加上链接&#xff09;&#xff0c;我在这不详细说明了&#xff0c;只说转换过程。 还是使用中…

Vue中如何进行分布式任务调度与定时任务管理

在Vue中进行分布式任务调度与定时任务管理 分布式任务调度和定时任务管理是许多应用程序中的关键功能之一。它们用于执行周期性的、异步的、重复的任务&#xff0c;例如数据备份、邮件发送、定时报告生成等。在Vue.js应用中&#xff0c;我们可以结合后端服务实现分布式任务调度…