UnityVR--组件7--动画事件BlendTree

news/2023/9/22 17:35:38 标签: unity, vr

目录

应用1:使用BlendTree实现站立和移动

应用2:人物跳跃事件&播放跳跃动画

应用3:开火动画事件&动画片段中建立事件监听


  上一篇(组件5--Animation动画)已经做了2个动画片段,HeroIdle和HeroJump,另外实现了简单的动画转场控制。本篇使用BlendTree来控制动画转场,并使用事件发送的方式来控制动画事件。

应用1:使用BlendTree实现站立和移动

   BlendTree用于对于两个或以上相似的动画混合(而不是过渡),比如人物在走路到达一定速度时与跑步的动画混合,或者在走动时同时向某个角度倾斜。

  下面使用BlendTree实现一下组件5--Animation动画中的站立和移动:

  1. 建立BlendTree:在状态机中点右键->CreateState->FromNewBlendTree

  

   2. 添加动画:在BlendTree上点右键->AddMotion,就会在右边的Inspector中添加一个Motion,添加两个Motion后,就会出现两个动画重叠转换的权重。分别将两个动画片段拖入下面的Motion名字框。下面这个Automate不要勾选,就可以自己配置权重。同时在Animator中也会看到这些动画片段:

  

  3. 脚本中添加动画事件:对于事件中心的修改,需要增加动画的事件类型、事件传输数据等。(关于事件中心,详见事件中心1等3篇)

  (1)添加事件类型——在EventType.c中,在枚举数据中添加下面这个播放动画的代码:

    OnPlayAnime=1005

  (2)添加事件传输数据——在EventDataBase.cs中,添加发送动画事件时同时需要发送的参数:

public class EventDataAnime:EventDataBase
{
    public EAnimeType animeType; 
    public float speed; //速度判断:站、走、跑
}

  (3)添加播放动画类型——建立一个枚举类型(也可以直接写在EventDataBase.cs里面),添加要播放的几种动画:

public enum EAnimeType
{
    Walk,Run,Jump,Idle,Fire
}

  4. 添加动画播放事件。在挂载Animator组件的节点上(我这里直接挂在主角Hero身上),新建一个AnimePlay.cs脚本:

public class AnimePlay : MonoBehaviour
{//使用事件控制动画
    private Animator animator;
    void Start()
    {
        animator = GetComponent<Animator>(); //获取同一节点上的Animator组件
        EventManager.Instance.AddEvent(EventType.OnPlayAnime, this, PlayAnime);
        //注册一个动画播放的事件,监听是此脚本
    }
    void PlayAnime(EventDataBase data)
    {
        var eventData = data as EventDataAnime;
        //根据传输的动画类型判断
        switch (eventData.animeType)
        {
            case EAnimeType.Idle:
                animator.SetFloat("changeFloat", 0);break;  
            //如果播放类型设置为站立Idle时,把转场参数设置为0,就播放站立动画
            case EAnimeType.Walk:
                animator.SetFloat("changeFloat", eventData.speed);break;
            //在移动时达到一定的速度就播放走路动画(其实是跳,因为没有做走路的动画效果)
        }
    }
}

  5. 修改主角行走脚本(移动事件的建立,详见新版InputSystem和EventManager),主角行走的脚本HeroMoveEvent.cs中的FixedUpdate()修改如下:

    void FixedUpdate()
    {
        movement.Set(moveInput.x, 0, moveInput.y);//moveInput的数据通过事件数据发送
        movement.Normalize();
        //检测是否有输入
        bool hInput = !Mathf.Approximately(moveInput.x, 0);
        bool vInput = !Mathf.Approximately(moveInput.y, 0);
        
        //增加:对于行走速度的判断,以便播放相应动画
        //定义一个isRunning的变量,用于判断上一帧是否有水平、垂直方向的输入

        if (isRunning&&!(hInput||vInput))
        {//判断如果上一帧是正在移动,而这一帧没有收到移动输入
            EventManager.Instance.SendEvent(EventType.OnPlayAnime, new EventDataAnime
            {//发送速度为0的事件,并播放站立动画
                animeType = EAnimeType.Idle,
                speed = 0
            });
        }

        isRunning = hInput || vInput;  //这一帧的isRunning赋值
        if (isRunning)
        {
            movement = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y, 0) * movement;
            //增加发送走路动画事件
            EventManager.Instance.SendEvent(EventType.OnPlayAnime, new EventDataAnime
            {
                animeType = EAnimeType.Walk,
                speed = movement.sqrMagnitude  //Vector3的API,把数值变为Float值
            }) ;
        }
        Vector3 lookForward = Vector3.RotateTowards(transform.forward, movement, rotateSpeed * Time.fixedDeltaTime, 360);
        targetRotation = Quaternion.LookRotation(lookForward);
        rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
        rb.MoveRotation(targetRotation);
    }

  6. 场景中的设置与上一篇 (组件5--Animation动画)一样,需要设置一个float参数作为转场的条件,也就是行走速度,初始值为0,当它达到0以上,也就是有速度时,就播放行走动画:

 最终效果,不动的时候播放站立动画,一呼一吸地,一旦发生移动就跳起来了:

应用2:人物跳跃事件&播放跳跃动画

  1. 按照上面的例子,先修改事件中心:

  (1)添加事件类型——在枚举EventType中加入:

OnPlayerJump=1006

  (2)在上面例子的(2)、(3)中已经添加了枚举的动画类型EAnimeType(里面已经写了Jump)和动画数据EventDataAnime,这里就不需要再修改了;

  2. 定义跳跃使用的按键:在Hero身上任何一个脚本的Update()中,直接接收一个控制跳跃的按键(当然也可以在新版InputSystem中定义,并设置监听跳跃事件,详见新版InputSystem),我这里统一放到InputManager.cs中了

        if (Input.GetKeyDown(KeyCode.Space))
        {//发送跳跃事件,在主角移动HeroMoveEvent中监听
            EventManager.Instance.SendEvent(EventType.OnPlayerJump, null);
        }

 3. 实现跳跃:挂在Hero身上

public class HeroMoveEvent : MonoBehaviour
{
    //定义一个跳跃力
    public float jumpGravity = -19.8f;  
    public float addJumpForce = 8;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        //注册一个主角跳跃事件,回调JumpAnime函数
        EventManager.Instance.AddEvent(EventType.OnPlayerJump, this, JumpAnime);
    }

    void JumpAnime(EventDataBase data)   
    {
        Physics.gravity = new Vector3(Physics.gravity.x, jumpGravity, Physics.gravity.z);
        rb.velocity = new Vector3(rb.velocity.x, addJumpForce / rb.mass, rb.velocity.y);
        //向上的力除以质量

        //跳的时候同时发送一个播放跳跃动画的事件
        //统一在hero身上的AnimePlayer接收
        EventManager.Instance.SendEvent(EventType.OnPlayAnime, new EventDataAnime { animeType = EAnimeType.Jump });
    }

  4. 上面这个例子中写的AnimePlayer.cs中已经注册了动画播放事件,并且定义了回调函数PlayAnime(),我们只要在回调函数的Switch中再加一个跳跃动画的判断就行

        switch (eventData.animeType)
        {
            …………省略…………
            case EAnimeType.Jump:
                animator.SetTrigger("JumpTrigger");break;
            //跳跃只需要Trigger控制,按一次跳一次
        }

  5. 对于场景中的Animator的设置,这里就不使用BlendTree了,简单的使用转场箭头连接一下:

   6. 这样就实现成功了,在运行时可以对于重力和跳跃力的参数进行调整,调到项目需要的状态

应用3:开火动画事件&动画片段中建立事件监听

  1. 建立一个动画片段Animation(HeroFire),作为开火时播放的动画。制作粗陋,就不展示了

  2. 在Animator中如下设置:将HeroFire动画片段放入,并建立与默认动画“BlendTree”的转场箭头,最后在左边建立一个Trigger类型的参数,取名为FireTrigger:

   3. 开火使用的按键在InputSystem中定义过,并且在InputManager.cs中有开火事件(OnFire())的定义,详见新版InputSystem,不再赘述。这里需要修改一下注册开火事件的脚本:

public class BulletFireEvent : MonoBehaviour
{
    public GameObject bullet;
    public bool canFire=true; //判断是否可以进行本次攻击
    void Start()
    {
        EventManager.Instance.AddEvent(EventType.OnPlayAnime, this, data =>
        {
            if ((data as EventDataAnime).animeType == EAnimeType.FireEnd) canFire = true;
        });
        EventManager.Instance.AddEvent(EventType.OnPlayerFire, this, callback =>
        {
            if (canFire == false) return;
            //判断上一次动画播放是否完成,接到canFire==true时才能往下操作
            canFire = false;
            EventManager.Instance.SendEvent(EventType.OnPlayAnime, new EventDataAnime
            {
                animeType = EAnimeType.Fire
            });
            //实例化子弹
            bullet = Resload.Instance.LoadPrefab("Bullet");
            bullet.SetActive(true);//激活
            bullet.transform.position = transform.position;
            bullet.transform.rotation = transform.rotation;
            Destroy(bullet, 2);//子弹2秒后自毁
        });
    }
    void OnFireEnd()
    {
            EventManager.Instance.SendEvent(EventType.OnPlayAnime, new EventDataAnime
            {
                animeType = EAnimeType.FireEnd
            });
    }
}

  这里需要说明的是:

  (1)增加了一个布尔变量-canFire,判断是否能够播放开火。这是因为必须等上一次的开火动画播放完成再播放;

  (2)注册了2个事件:OnPlayAnime和OnPlayerFire,一个用于开火,一个用于播放动画;

  (3)在上面应用1中建立的动画类型的枚举数据(EAnimeType)中再增加一个FireEnd的数据,用于传输动画是否已经播完的信号

public enum EAnimeType
{
    Walk, Run, Jump, Idle, Fire, FireEnd
}

  (4)最后的这个OnFireEnd()函数,是需要到开火动画去监听的,设置方法看步骤4.

  4. 打开HeroFire的动画片段,在结束处加入一个动画事件:

   5. 点击这个动画事件,在Inspector面板中将回调函数设置为OnFireEnd

    6.完整的运行结果:开火时发一个子弹,并且小鬼的身子转一下。可以看到在开火动画播放完成后,布尔参数canFire就变成true允许下一次动画的执行。


http://www.inspinia.net/a/542666.html

相关文章

python3写一个http接口服务(get, post),给别人调用6

python3写一个http接口服务(get, post)&#xff0c;给别人调用6 一、python3写一个http接口服务(get, post)&#xff0c;给别人调用6 近年来异步web服务器比较火热&#xff0c;例如falcon/bottle/sanic/aiohttp&#xff0c;今天也来玩玩sanic。 Sanic是一个支持Python 3.7的w…

Qt6 C++基础入门3 对话框与MainWindow

目录 对话框MainWindow菜单工具栏 对话框 目前的对话框主要有以下几大类 文件对话框( QFile Dialog)消息对话框( QMessageBox)输入对话框( QInputDialog)颜色对话框( QColorDialog)字体对话框( QFontDialog) 这是七大对话框及其基本用法的实例参考&#xff0c;所有代码都写在…

ETC人车关系查询-ETC人车关系查询api接口

接口地址&#xff1a; https://登录后显示/api/189/363(支持:http/https)) 接口页面&#xff1a;https://www.wapi.cn/api_detail/189/363.html 网站地址&#xff1a;https://www.wapi.cn 接口简介&#xff1a;核验指定人员/企业是否是指定车辆的 ETC 开户人、车辆所有人或 E…

一文说清,4G语音工牌与WIFI和蓝牙语音工牌的区别

作为一种创新的无线音频采集和传输设备&#xff0c;4G语音工牌在许多行业和领域都展现出了巨大的优势和广泛的应用场景。 比如在销售场景和服务场景&#xff0c;利用4G语音工牌和NLP、语音识别、机器学习等技术结合&#xff0c;可实现&#xff1a; 帮销售型企业&#xff1a;提…

【 Python 全栈开发 - WEB开发篇 - 29 】MySQL初步

文章目录 一、MySQL介绍二、SQL语言三、MySQL安装与配置第一步&#xff1a;下载压缩文件第二步&#xff1a;解压第三步&#xff1a;配置第四步&#xff1a;登录 一、MySQL介绍 MySQL 是一个开源的关系型数据库管理系统&#xff0c;它使用 Structured Query Language&#xff0…

计算机网络开荒2.2-Socket编程

文章目录 一、Socket概述二、Socket API 概述三、WinSock常用API3.1 常用API3.1.1 WSAStartUP3.1.2 WSACleanup3.1.3 Socket3.1.4 Closesocket3.1.5 bind3.1.6 listen3.1.7 connect3.1.8 accept3.1.9 send, sendto3.1.10 recv, recvfrom3.1.11 etsockopt, getsockopt 3.2 网络字…

webgpu之旅03

19854902 319854902 319854902 319854902 webgpu交Q流群我们找个例子看看别人的renderer three.js v152 首先init函数 看见中间有个对象 WebGPURenderPipelines 跟进去看看 这个构造函数里可以看见有这么些数据 get( renderObject ) {const device this.device;const cache …

读改变未来的九大算法笔记07_搜索引擎

1. 车库轶事 1.1. 1939年 1.1.1. 戴夫休利特&#xff08;Dave Hewlett&#xff09; 1.1.1.1. 惠普&#xff08;Hewlett-Packard&#xff09; 1.2. 1976年 1.2.1. 蒂夫乔布斯&#xff08;Steve Jobs&#xff09;和史蒂夫沃兹尼亚克&#xff08;Steve Wozniak&#xff09; …

【工业控制系统安全】深入了解 ICS612:ICS 网络安全:第 1 部分

ICS 从业者可以立即在实际情况中使用他们的 ICS612 培训。 降落飞机 我认识一家生产工厂的首席执行官&#xff0c;我们就叫他比尔吧&#xff0c;他希望他的关键团队成员真正了解他的运营团队每天为实现生产目标而承受的压力。比尔还希望他的经理和支持人员能够理解“让它发生”…

chatgpt赋能python:Python快速打开:如何提高Python执行速度

Python 快速打开&#xff1a;如何提高 Python 执行速度 介绍 Python 是一种解释型语言&#xff0c;由于其简洁易读&#xff0c;广泛用于数据科学、机器学习、Web 开发等领域。然而&#xff0c;它的执行速度相对较慢&#xff0c;这通常是由于其解释器中面临的硬件资源限制以及…

C#winform多国语言应用实例

我们在开发项目中,一般需要软件支持多种语言,供不同客户使用。本文实例讲解实现办法。 1 窗体项目创建 添加控件MenuStrip、comboBox及Button,并修改对应显示文本,combobox编辑项输入英语 确定窗体的Localizable属性为true,自动创建Form1.resx,为False时,没有Form1.r…

MATLAB使用技巧之局部放大图的制作及文本箭头的便捷设置

MATLAB使用技巧之局部放大图的制作及文本箭头的便捷设置 文章目录 MATLAB使用技巧之局部放大图的制作及文本箭头的便捷设置制作局部放大图的方法文本箭头的便捷设置小结 本文主要介绍如何在MATLAB中绘制局部放大图和如何便捷地设置文本箭头的相关内容&#xff0c;以作后续回顾之…

可视化报表系统推荐

在当今信息时代&#xff0c;数据的处理和分析已经成为了企业管理中不可或缺的一部分。而报表则是这个过程中最常见的工具之一。手工写报表虽然简单易懂&#xff0c;但是随着数据量的增加&#xff0c;这种方式逐渐暴露出许多痛点。比如说&#xff1a; 1.时间耗费长&#xff1a;…

占据80%中国企业出海市场,亚马逊云科技如何为出海客户提供更多资源和附加值

亚马逊云科技就可以做到&#xff0c;作为占据80%中国企业出海市场的亚马逊云科技&#xff0c;其覆盖全球的业务体系&#xff0c;从亚马逊海外购、亚马逊全球开店、亚马逊智能硬件与服务&#xff0c;Amazon Alexa&#xff0c;Amazon Music都是属于亚马逊云科技“梦之队”的一员。…

【嵌入式环境下linux内核及驱动学习笔记-(15-1)例程】

目录 1、在APP直接调用标准文件IO操作I2C(针对学习笔记-15的15.3节)1.1 mail.c1.2 mpu6050.h1.3 mpu6050.c1.4 Makefile 2、以外称id的方式进行匹配的i2c驱动2.1 mpu6050.h2.2 mpu6050_i2c_client.c2.3 mpu6050_i2c_driver.c2.4 read_mpu.c 测试的应用层APP2.5 Makefile 3、以设…

大学生网络工程想走网络安全方向该怎么规划?

明确需求,确定方向 网络安全 网络安全 是一个很广的概念&#xff0c;涉及的岗位也是非常多的&#xff0c;有安全服务、安全运维、渗透测试、web安全、安全开发、安全售前等等。可以看看下面每个岗位的要求与自身兴趣能力匹配度再决定最适合自己的方向。 渗透测试/Web安全工程师…

第七章 Electron Vue3实现音乐播放器

一、介绍 &#x1f351; &#x1f351; &#x1f351; 一个音乐播放器应该具备播放、暂停、上一首、下一首、播放模式&#xff08;单曲循环、列表循环、顺序播放……&#xff09;。除了这些比如还可以扩展进度条的展示、拖拽、音量大小的调节&#xff0c;如果资源允许的话可以…

【3步教程】如何使用商城小程序源码打造自己的商城?

作为电商行业的领头人&#xff0c;在移动端上拥有一款独立小程序绝对是不能缺少的&#xff0c;而使用商城小程序源码打造自己的商城则是最佳的选择之一。本文将教您如何在3步之内&#xff0c;快速高效地使用商城小程序源码&#xff0c;打造属于自己的小程序商城。 步骤一&…

Netty核心源码剖析(四)

1.Netty心跳(heartbeat)服务源码剖析 1>.Netty作为一个网络框架,提供了诸多功能,比如编码解码等,Netty还提供了非常重要的一个服务–心跳机制heartbeat.通过心跳检查对方是否有效,这是RPC框架中是必不可少的功能.下面我们分析一下Netty内部心跳服务源码实现; 2>.Netty提…

【算法基础】拓扑排序及实战

一 、概览 这里涉及到图的概念&#xff0c;感兴趣的同学请移驾 –>图<– 下面还有两个相关概念&#xff0c;大概说一下&#xff1a; 1.1 有向无环图 定义&#xff1a;在图论中&#xff0c;如果一个有向图从任意顶点出发无法经过若干条边回到该点&#xff0c;则这个图是…