【Unity3D小技巧】Unity3D中判断Animation以及Animator动画播放结束,以及动画播放结束之后执行函数

news2024/9/29 1:17:11

推荐阅读

  • CSDN主页
  • GitHub开源地址
  • Unity3D插件分享
  • 简书地址
  • 我的个人博客

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

在日常开发中,可能会遇到要判断Animation或者Animator动画播放是否结束的情况。

判断Animation是否结束可以这么写:

using System;
using System.Collections;
using UnityEngine;

public class AnimationPlayControl : MonoBehaviour
{
    Animation ani;
    void Update()
    {
        AnimationState state = ani["Open"];
        if (state.normalizedTime >= 1) 
        {
            // 判断动画播放结束normalizedTime的值为0~1,0为开始,1为结束。
            Debug.Log("动画播放完毕");
        }
    }
}

或者简单一点:

using System;
using System.Collections;
using UnityEngine;

public class AnimationPlayControl : MonoBehaviour
{
    Animation ani;
	void Start()
	{
		if(!ani.isPlaying)
		{
			Debug.Log("没有播放动画,或播放结束动画");
		}
	}
}

判断Animator是否结束可以这么写:

using System;
using System.Collections;
using UnityEngine;

public class AnimationPlayControl : MonoBehaviour
{
    Animator anir;
    void Start()
    {
        //获取动画层 0 指Base Layer.
        AnimatorStateInfo stateinfo = anir.GetCurrentAnimatorStateInfo(0);
        //判断是否正在播放walk动画.
        if (!stateinfo.IsName("Base Layer.walk"))
        {
        	Debug.Log("没有播放walk动画,或播放结束动画");
        }
    }
}

但是,如果说要判断动画结束之后再执行某些事件就有些麻烦,首先需要在Update里面一直判断是否播放完,播放完再去执行事件。

消耗性能,也不好管理,所以就写了一个迭代器也就是协程来判断动画是否结束,结束后执行回调函数。

二、Animation动画播放结束判断

2-1、第一种协程写法

代码参考:

using System;
using System.Collections;
using UnityEngine;

public class AnimationPlayControl : MonoBehaviour
{
    Animation ani;
    void Start()
    {
        PlayAnimation(ani, "Open",
        () =>
        {
            Debug.Log("动画播放前执行代码");
        },
        () =>
        {
            Debug.Log("动画播放完执行代码");
        });
    }

    // 封装函数
    public void PlayAnimation(Animation animation, string clipName, Action startAct = null, Action endAct = null)
    {
        StartCoroutine(PlayAnimationItor(animation, 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>
    IEnumerator PlayAnimationItor(Animation animation, string clipName, Action startAct, Action endAct)
    {
        startAct?.Invoke();

        animation.Play(clipName);
        yield return new WaitForSeconds(animation[clipName].length);

        endAct?.Invoke();
    }
}

PS:主要是使用了协程中的new WaitForSeconds也就是等待X秒,这里就是等待动画播放的X秒后执行委托函数,更加详细的协程可以参考我其他文章,这里就不详细说明了。

2-2、第二种协程写法

using System;
using System.Collections;
using UnityEngine;

public class AnimationPlayControl : MonoBehaviour
{
    Animation ani;
    void Start()
    {
        PlayAnimation(ani, "Open",
        () =>
        {
            Debug.Log("动画播放前执行代码");
        },
        () =>
        {
            Debug.Log("动画播放完执行代码");
        });
    }

    // 封装函数
    public void PlayAnimation(Animation animation, string clipName, Action startAct = null, Action endAct = null)
    {
        StartCoroutine(PlayAnimationItor(animation, 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(Animation animation, string clipName, Action startAct, Action endAct)
    {
        startAct?.Invoke();

        AnimationState animationState = animation[clipName];
        animation.Play(clipName);
        yield return StartCoroutine(new WaitForEndOfAnim(animationState));

        endAct?.Invoke();
    }
}

// 实现WaitForEndOfAnim迭代器
public class WaitForEndOfAnim : IEnumerator
{
    AnimationState m_animState;
    public WaitForEndOfAnim(AnimationState animState)
    {
        m_animState = animState;
    }
    public object Current
    {
        get
        {
            return null;
        }
    }
    public bool MoveNext()
    {
        return m_animState.enabled;
    }
    public void Reset()
    {
    }
}

这种方式,实现WaitForEndOfAnim迭代器,在动画播放完后执行后面的代码。

三、Animator动画播放结束判断

首先,要明白Animator是动画状态机,是用来控制动画片段,然后去切换动画片段的,如下图所示:

在这里插入图片描述
所以说,Animator默认就会开始播放一种动画,不论是Idle动画还是Walk动画,总会播放一种动画,所以就不用像Animation去Play某一个动画了,只需要判断当前动画是否播放完即可。

代码参考如下,两种方法写一起了:

using System;
using System.Collections;
using UnityEngine;

public class AnimationPlayControl : MonoBehaviour
{
    Animator ani;
    void Start()
    {
        PlayAnimation(ani, "Open",
        () =>
        {
            Debug.Log("动画播放前执行代码");
        },
        () =>
        {
            Debug.Log("动画播放完执行代码");
        });
    }

    // 封装函数
    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, Action endAct)
    {
        startAct?.Invoke();

        AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
        yield return StartCoroutine(new WaitForEndOfAnimr(animatorStateInfo,clipName));

        endAct?.Invoke();
    }

    /// <summary>
    /// Animation动画播放迭代器
    /// </summary>
    /// <param name="animation">Animation组件</param>
    /// <param name="clipName">clip片段名</param>
    /// <param name="startAct">委托函数</param>
    /// <param name="endAct">委托函数</param>
    /// <returns></returns>
    IEnumerator PlayAnimationItor2(Animator animator, string clipName, Action startAct, Action endAct)
    {
        startAct?.Invoke();
        yield return new WaitForSeconds(animator.GetCurrentAnimatorClipInfo(0)[0].clip.length);
        endAct?.Invoke();
    }
}

// 实现WaitForEndOfAnim迭代器
public class WaitForEndOfAnimr : IEnumerator
{
    AnimatorStateInfo m_animState;
    public WaitForEndOfAnimr(AnimatorStateInfo animState,string clipName)
    {
        m_animState = animState;
    }
    public object Current
    {
        get
        {
            return null;
        }
    }
    public bool MoveNext()
    {
        return m_animState.IsName(clipName);
    }
    public void Reset()
    {
    }
}

四、后记

结束,本篇文章讲解了Animation和Animator动画播放结束的判断代码。

以及如何实现在Animation和Animator动画播放结束判断,并且执行回调函数的实现。


你的点赞就是对博主的支持,有问题记得留言:

博主主页有联系方式。

博主还有跟多宝藏文章等待你的发掘哦:

专栏方向简介
Unity3D开发小游戏小游戏开发教程分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。
Unity3D从入门到进阶入门从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。
Unity3D之UGUIUGUIUnity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。
Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。
Unity3D之数据集合数据集合数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。
Unity3D之VR/AR(虚拟仿真)开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。
Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法,插件介绍等
Unity3D之日常开发日常记录主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等
Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。

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

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

相关文章

MySQL workbench数据表和数据结构

数据表和数据结构的关系 数据表 学号姓名位置26002351李晓丽126002589张明伟226003214李雪冬326002132汪涵426006541邱明罕526003654李丽6 怎样去描述上面的数据表&#xff0c;用【数据表结构】表示 表头字段名字段类型位数备注学号xuehao整数/字符8 姓名xingming字符4 座…

煤矿人员精确定位解决方案,维护作业人员生命安全

近日&#xff0c;应急管理部党委书记、部长王祥喜主持召开全国安全防范工作视频会议。会议强调&#xff0c;要深刻吸取内蒙古露天煤矿坍塌等重特大事故教训&#xff0c;举一反三全面排查整治重点行业领域重大安全隐患&#xff0c;坚决遏制重特大事故&#xff0c;切实维护人民群…

【数据结构·考研】后序线索二叉树

之前我们介绍了中序线索二叉树的构造、遍历、寻找前趋和寻找后继&#xff1b;先序线索二叉树的构造、遍历、寻找后继。先序线索二叉树无法解决寻找前趋的任务&#xff0c;中序线索二叉树既可以寻找前趋结点也可以寻找后继结点。 今天我们再来看一下后序线索二叉树的构造&#…

apt-get通过代理更新系统

apt-get通过代理更新系统1. 源由2. 需求3. 分析4. 步骤4.1 安装CCProxy4.2 配置CCProxy4.3 apt-get更新4.4 apt-get升级4.5 apt-get安装5. 补充资料 命令行设置代理6. 参考资料1. 源由 apt-get经典操作就是通过网络与服务器通信&#xff0c;下载相应的包来安装和更新软件。 这…

docker容器内安装gcc(trunk 最新版本)以及LLVM

1、docker内部只有wget以及git命令 项目需要&#xff0c;得更新docker容器中的gcc和LLVM版本但是由于没有预先安装apt、apt-get以及yum&#xff0c;导致很多安装过程就是鸡生蛋蛋生鸡反应。暂时没有找到合适的解决的方法&#xff0c;如果有大佬知道的话&#xff0c;欢迎留言哈…

ZeroTier实现内网穿透详细教程,无需公网IP,实现异地组网

ZeroTier实现内网穿透详细教程&#xff0c;无需公网IP&#xff0c;实现异地组网ZeroTier1.官网注册账号&#xff0c;创建自己的局域网段2.点击创建好的网络&#xff0c;进入设置界面进行设置3.下载客户端&#xff0c;安装客户端&#xff0c;然后连接到网络中4.加入网络成功后&a…

pocsuite3安装及使用

pocsuite3安装及使用简介项目地址环境配置及安装环境要求安装&#xff08;详情可以参考[https://pocsuite.org/](https://pocsuite.org/)&#xff09;使用方法运行模块加载目标参数&#xff1a;Console模式查看有哪些模块使用Telnet 弱密码模块这里以flask模板注入漏洞为例pocs…

阿里云短信验证

1.了解阿里云用户权限操作 需要通过个人账户获得 授权码&#xff08;id、密码&#xff09;&#xff0c;再通过这些信息获得服务 阿里云网址 &#xff1a;https://www.aliyun.com/ 1.登陆阿里云服务器2.进入个人账号然后点击 AccessKey 管理3.创建用户组4.添加用户组权限&…

SYSU程设c++(第三周) 对象类、类的成员、类与结构体的区别、类的静态成员

对象&类 类用于指定对象的形式&#xff0c;它包含数据的表示方法和用于处理数据的方法。 • 类中的数据和方法称为类的成员。 • 函数在一个类中也被称为类的成员。 定义一个类&#xff0c;其效果是定义一个数据类型的蓝图。它定义了类的对象包括了什么&#xff0c;以及可…

C++基础了解-08-C++运算符

C运算符 一、C 运算符 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符&#xff0c;并提供了以下类型的运算符&#xff1a; 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 杂项运算符 二、算术运算符 下表显示了 C 支持的算术运算符…

led灯性价比最高的是哪款?2023最新的哪种led灯质量比较好

Led作为一种固态半导体&#xff0c;具有自发光、高可控性的特点&#xff0c;高效节能&#xff0c;省电环保&#xff0c;并且根据材料的不同&#xff0c;发出的光线颜色也不同&#xff0c;因此广泛用于各种照明灯具&#xff0c;台灯也不例外。 作为一种适合工作学习或者工作休闲…

跑步耳机入耳好还是不入耳好、十大跑步运动耳机品牌排行榜推荐

健身房经常会播放一些节奏较快的歌曲&#xff0c;这样能够激发大家在运动过程中的动力&#xff0c;所以运动时聆听音乐确实比较有效果&#xff0c;居家运动、室外跑步时选择运动耳机就变成了刚需&#xff0c;首先不能影响其他人、佩戴时要稳定&#xff0c;音质和续航要有保证&a…

npm install 原理

npm基本使用node.jsNode.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。在任何地方安装了node&#xff0c;那么就可以运行JavaScript。所以在服务器上就可以运行js了。js就全栈了。node安装的同时就安装了npm。直接去官网下载&#xff0c;双击安装即可。安装完毕之后…

java基于springboot仓库管理系统的设计与实现

项目介绍 基于 SpringBoot 的仓库管理系统拥有多种角色&#xff0c;可供用户自定义使用。 功能模块 一、业务模块 1、客户管理 2、供应商管理 3、商品管理 4、商品进货管理 5、商品退货管理 6、商品销售管理 7、商品销售退货管理 二、系统模块 菜单管理&#xff0c;角色管…

Java高级工程师特别熟悉的js基础 | 面向对象编程/原型链/继承

面向对象编程/原型链/继承 面向对象编程 什么是面向对象编程&#xff1f; 面向对象是⼀种编程思想&#xff0c;经常被拿来和⾯面向过程⽐比较。其实说的简单点&#xff0c;面向过程关注的重点是动词&#xff0c;是分析出解决问题需要的步骤&#xff0c;然后编写函数实现每个步…

WIFI标签操作步骤

1. 打开并设置手机WIFI热点&#xff0c;设置SSID为ESL&#xff0c;密码为123456789&#xff08;如下图&#xff09; ​ 2. 运行APP&#xff0c;设置要接入的WIFI名称密码等信息&#xff08;如下图&#xff09; ​ 3. 长按背面按键&#xff08;长按2-3秒&#xff09;&#xff0c…

TypeScript 深度剖析:TypeScript 的理解?与 JavaScript 的区别?

一、是什么 TypeScript 是 JavaScript 的类型的超集&#xff0c;支持ES6语法&#xff0c;支持面向对象编程的概念&#xff0c;如类、接口、继承、泛型等 超集&#xff0c;不得不说另外一个概念&#xff0c;子集&#xff0c;怎么理解这两个呢&#xff0c;举个例子&#xff0c;如…

MYSQL 最大连接数

MYSQL 最大连接数&#xff1f; 最大连接数也就是mysql服务最大支持多少客户端连接服务 查看服务支持最大连接数&#xff1a; show variables like %max_connections%;如下: 如何查看 MYSQL 服务被多少个客户端连接了&#xff1f; show processlist;如下&#xff1a; 其中 …

数位dp--Windy数

题目 思路 大体思路其实也跟第一篇博客类似&#xff0c;用前缀和的思想处理区间的方案数&#xff0c;然后求方案数则是通过把每一位数都拆分来&#xff0c;然后根据两种选择0-an-1和选an两种情况进行判断&#xff0c;但是因为前导零会对结果产生不一样的结果&#xff08;比如0…

企业的ICP域名注册,你知道吗?

ICP域名备案查询的api接口&#xff0c;是企业在短时间内获得中沃公司最新数据的API接口。还可以帮助用户快速了解公司信息。基于域名的注册信息实时查询&#xff0c;适合对注册信息变更及时性要求较高的用户。通过ICP信息可以确认企业在互联网中的更多活动轨迹。企业的ICP域名注…