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.mzph.cn/news/101233.shtml

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

相关文章

基于 chinese-roberta-wwm-ext 微调训练中文命名实体识别任务

一、模型和数据集介绍 1.1 预训练模型 chinese-roberta-wwm-ext 是基于 RoBERTa 架构下开发&#xff0c;其中 wwm 代表 Whole Word Masking&#xff0c;即对整个词进行掩码处理&#xff0c;通过这种方式&#xff0c;模型能够更好地理解上下文和语义关联&#xff0c;提高中文文…

振弦传感器和振弦采集仪应用隧道安全监测的解决方案

振弦传感器和振弦采集仪应用隧道安全监测的解决方案 现代隧道越来越复杂&#xff0c;对于隧道安全的监测也变得越来越重要。振弦传感器和振弦采集仪已经成为了一种广泛应用的技术&#xff0c;用于隧道结构的监测和评估。它们可以提供更精确的测量结果&#xff0c;并且可以在实…

0基础学习VR全景平台篇 第104篇:720全景后期软件安装

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 摄影进入数码时代&#xff0c;后期软件继承“暗房工艺”&#xff0c;成为摄影师表达内在情感的必备工具。 首先说明&#xff0c;全景摄影与平面摄影的一个显著的区别是全景图片需…

ChatGPT私有数据结合有什么效果?它难吗?

ChatGPT的出现可谓是惊艳了全世界&#xff0c;ChatGPT的问答能力通过了图灵测试&#xff0c;使其回答问题的方式与人类几乎无法区分。大家不甘于只在官方的对话页面问答&#xff0c;想利用 GPT 模型的自然语言能力结合私有数据开拓更多的应用场景。 | ChatGPT私有数据结合特点 …

滚珠螺母在工业机器人中的应用优势

工业机器人是广泛用于工业领域的多关节机械手或多自由度的机器装置&#xff0c;具有一定的自动性&#xff0c;可依靠自身的动力能源和控制能力实现各种工业加工制造功能。滚珠螺母作为工业机器人中的重要传动配件&#xff0c;在工业机器人的应用中有哪些优势呢&#xff1f; 1、…

SpringMVC修炼之旅(1)什么是SpringMVC

一、什么是MVC 1.1概述 MVC是模型(Model)、视图(View)、控制器(Controller)的简写&#xff0c;是一种软件设计规范。 是将业务逻辑、数据、显示分离的方法来组织代码。 MVC主要作用是降低了视图与业务逻辑间的双向偶合。 MVC不是一种设计模式&#xff0c;MVC是一种架构模式…

主从Reactor高并发服务器

文章目录 Reactor模型的典型分类单Reactor单线程单Reactor多线程多Reactor多线程本项目中实现的主从Reactor One Thread One Loop各模型的优点与缺点 项目分解Reactor服务器模块BufferSocketChannelEpollerTimerWheelEventLoopAnyConnectionAcceptorLoopThreadLoopThreadPoolTc…

UDP报文结构

文章目录 一、UDP报头1.1源端口号1.2目的端口号1.3UDP报文长度1.4UDP校验和(checksum) UDP报头和UDP载荷(payload)之间的拼接可以认为是一个“字符串拼接”&#xff0c;里面是二进制数据。 一、UDP报头 UDP报头分成4个部分&#xff0c;每个部分2个字节。分别是&#xff1a; 1…

【大数据】hadoop安装部署(学习笔记)

一、集群组成概述 Hadoop集群包括两个集群&#xff1a;HDFS集群、YARN集群 两个集群逻辑上分离、通常物理上在一起 两个集群都是标准的主从架构集群 HDFS集群&#xff08;分布式存储&#xff09;&#xff1a; 主角色&#xff1a;NameNode从角色&#xff1a;DataNode主角色…

基于安卓android微信小程序的旅游系统

项目介绍 随着人民生活水平的提高,旅游业已经越来越大众化,而旅游业的核心是信息,不论是对旅游管理部门、对旅游企业,或是对旅游者而言,有效的获取旅游信息,都显得特别重要.自助定制游将使旅游相关信息管理工作规范化、信息化、程序化,提供旅游景点、旅游线路,旅游新闻等服务本…

闲聊servlet的常见注册方式

大家好&#xff0c;我是G探险者。 servlet大家都不陌生&#xff0c;当开发 Web 应用程序时&#xff0c;注册 Servlet 是一个常见的任务&#xff0c;因为 Servlet 是处理 HTTP 请求和生成 HTTP 响应的核心组件之一。在不同的开发环境和框架中&#xff0c;有多种方法可以注册 Ser…

Table.Group系列_第4参数为全局的情况下,利用第5参数进行分组汇总

原始数据: 部门与职位存在于同一列中 实现功能: 根据筛选条件,可对部门或职位进行统计汇总第一列列名根据筛选自动变更,显示当前统计的维度 实现方式: 1. 构建筛选器内容 在任意空白单元格内输入需要筛选的内容 2. 插入"组合框"控件,并进行相应设置 从开发工具…

麒麟系统加密/麒麟系统防泄密

​深信达网络科技有限公司自主研发的深信达主机加固系统软件V2.0、深信达沙盒防泄密系统软件V5.0&#xff0c;与麒麟软件完成兼容认证&#xff0c;并被纳入麒麟软件安全生态联盟成员之一。 麒麟软件主要面向通用和专用领域打造安全创新操作系统产品和相应解决方案&#xff0c;以…

GitHub详细教程

将代码推送到GitHub仓库涉及一系列的步骤。以下是详细的步骤说明&#xff1a; 创建一个新的仓库&#xff08;如果还没有的话&#xff09;&#xff1a; 访问 GitHub。登录您的帐户。点击页面右上角的图标&#xff0c;然后选择“New repository”。填写仓库名称、描述等信息&…

Matlab矩阵——矩阵行列互换

问题&#xff1a;如何将 1*n 的矩阵转换为指定 M*N 的矩阵&#xff0c;或者将 M*N 的矩阵转换为 1*n 的矩阵&#xff1f; 处理方法&#xff1a;使用 reshape 函数进行矩阵的行列互换 分两种情况如下&#xff1a; 一、将 1*n 的矩阵转换为指定 M*N 的矩阵 假如有4个坐标值&a…

大型语言模型:DistilBERT — 更小、更快、更便宜、更轻

一、介绍 近年来&#xff0c;大型语言模型的演进速度飞速发展。BERT成为最流行和最有效的模型之一&#xff0c;可以高精度地解决各种NLP任务。在BERT之后&#xff0c;一组其他模型随后出现在现场&#xff0c;也展示了出色的结果。 很容易观察到的明显趋势是&#xff0c;随着时间…

推荐开源工具带带弟弟ocr_ddddocr_各种验证码都可以识别_滑动_点击_等等---验证码识别工作笔记001

这个很强大了,常见的各种验证码都可以识别,如果你项目上也有需要,比如需要实现系统的自动登录,这个时候就很有用了,这里仅仅给出方案,具体如何用,用的时候在做研究吧,好东西要记录,分享给需要的人.使用的时候 自己去查一下如何使用非常简单. 支持点击的验证码,支持数字验证码就…

Three.js

定义&#xff1a; three,js,一WebGL引擎&#xff08;也叫库&#xff09;&#xff0c;基于javaScript,可直接运行GPU驱动游戏与图形驱动应用于浏览器。其库提供大量特性与API以绘制3D场景于浏览器。 WebGL:Web图形库&#xff0c;一组浏览器的API,可以无需其他插件&#xff0c;独…

【C++】哈希

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; C学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最大…

rust cfg的使用

前提是一个crate倒入另一个crate。 先看结构 test_lib目录结构 这与另一个crate处于同一个目录,所以另一crate倒入的时候在Cargo.toml中使用如下语句。 test_lib = {path = "../test_lib" }先在test_lib/src/abc/abc.rs中添加没有cfg的两个函数做测试。 pub fn…