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…

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

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

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

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

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

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

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

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

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

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

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

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

【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…

ViewModifier/视图修饰符, ButtonStyle/按钮样式 的使用

1. ViewModifier 视图修饰符 1.1 创建默认按钮视图修饰符 ViewModifierBootcamp.swift import SwiftUI/// 默认按钮修饰符 struct DefaultButtonViewModifier: ViewModifier{let bcakgroundColor: Colorfunc body(content: Content) -> some View {content.foregroundColor…

C/C++之自定义类型(结构体,位段,联合体,枚举)详解

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂。 目录 个人主页&#xff1a;点我进入主页 …

MySQL 安装+启动+报错的解决方案

目录 一、安装准备 1.1 下载 1.2 版本说明 二、安装步骤 2.1 解压缩 2.2 配置环境变量 2.3 配置文件 2.4 安装 2.5 启动/停止服务 三、使用说明 3.1 用户名密码登录 3.1 设置用户名密码 四、卸载步骤 4.1 卸载服务 五、安装问题 六、启动问题 6.1 提示【服务无…

web基础和http协议

1.DNS解析的三种方式 DNS解析&#xff1a; 网站都是域名&#xff1a;dns解析的作用是把域名解析成ip地址 迭代&#xff1a;从跟域名到二级域 返回用户的过程&#xff1a;递归---运营商--本地hosts---用户 三种方式&#xff1a; /etc/hosts 本地解析&#xff0c;速度最快&…

岩土工程安全监测无线振弦采集仪在无线组网的关键要点

岩土工程安全监测无线振弦采集仪在无线组网的关键要点 岩土工程是一种奇特而又极其重要的工程。它涉及到土地、岩石、气候等等因素&#xff0c;需要重视安全因素。而无线振弦采集仪作为一种常用的监测设备&#xff0c;可以采集岩土工程中的振动数据&#xff0c;从而确保工程的…