当前位置: 首页 > news >正文

【Unity/Animator动画系统】多层动画状态机实现角色的基本移动

文章目录

    • 前言
    • 实现
      • 顶层
      • 地面状态
        • 四方向混合树
        • 计算动画所需参数
      • 空中状态
      • 分层动画

前言

最近打算做个Rougelike + RPG + 塔科夫 混搭风格的冒险游戏。暂且就当是一个有随机元素,有基地,死亡会掉落物品的近战塔科夫罢。

花了三天时间,整合了Mixamo的动画和模型资源,通过改动一点Unity自带的第三人称模板的控制器实现移动和动画控制,然后自己做了个动画状态机。写这篇主要是记录制作动画状态机时出现的问题状况和解决方案。

当下动画状态机实现了以下特性

  • 基于人物速度的站立到奔跑的混合动画
  • 基于人物朝向和速度的四方向混合动画(行走和蹲伏)
  • 基于人物速度的跳跃和坠落的混合动画(站立跳跃和奔跑跳跃)
  • 通过分层动画实现不同的武器装备和攻击动画

我自我认为这个动画状态机写的还算是比较简洁的,一开始接触Unity的动画系统,第一感觉就是这也不好复制,那也不好复制,一直在重复赋值,缺乏批量操作。现在呢,现在也这么觉得。

Unity状态机如果不维护好切换关系和划分层级,很快就会连的跟个蜘蛛网一样。我基于之前写过的角色状态机的经验,决定将动画状态机和角色状态机分一样的层,维护基本一致的转换关系,并且条件尽量只和角色自身属性有关,尽可能少的通过操作来判断转换条件。

在具体说明这个动画状态机前,先看一下Unity官方给的这个ThirdPersonController,这东西把所有东西都塞进了一个类中,东西全是挺全,就是写和扩展肯定是地狱级别的,我在添加控制的Animator的参数时,需要修改多处代码,十分甚至九分的麻烦,现在只是原型设计,后续肯定会把它重构成状态机结构的。


实现

顶层

先看一下状态机的拓扑图

在这里插入图片描述

顶层拓扑图维护了最高层的关系,即玩家从地面到空中的转换,引起这种变化的原因只有两个

  • 玩家输入Jump操作
  • 玩家悬空

而从空中状态返回到地面状态则只有一种原因,即玩家落地


地面状态

接下来再看看子状态机GroundState:

在这里插入图片描述

这一层主要维护所有的地面操作,包括正常的四方向混合和蹲下的四方向混合,二者之间通过玩家是否按下下蹲操作进行转换。

因为外层的状态机不会在条件满足时自动终止内部的操作,因此仍需要重复对二者进行判断是否离开地面或者玩家是否跳跃的条件进行判断,进而确定何时离开状态机。

四方向混合树

Idle/Walk/Run看名字就知道是个混合树。其内部长这样:

在这里插入图片描述

先通过方向混合得到四方向动画,再通过速度应用动画。这里只做了向前的奔跑操作,是我个人需求。在我的操作方式中,玩家默认是会自动朝向移动方向的(也是官方示例的默认功能),因此不需要其他的奔跑方向。但是我额外添加了一个瞄准操作,该操作会使玩家始终面向摄像机方向,此时玩家向前方以外的方向移动时,速度会被限制,无法奔跑,因此只需要其他方向的行走动画,也不需要其他方向的奔跑动画。

当然,四方向的移动效果并不好,如果有条件肯定是八个方向会更好,因为只有四方向对于斜向移动会导致插值出滑步。

下蹲和这个大同小异,由于下蹲时不能奔跑,速度恒定,因此也无需混合速度这一维数据。

这里再说一下如何获得图上的DirectionX和DirectionY参数。

计算动画所需参数

玩家速度和朝向一致时得到向量{0, 1},相反得到{0, -1},垂直且速度在朝向的右边得到{1, 0},左边则是{-1, 0}。这个是最终得到的输入要求,通过这个要求我们就可以得到这样的函数:

private Vector2 GetXYDirectionRelativeControllerRotation()
{// 获取玩家控制器的前向方向(面向方向)Vector2 facingDirection = new Vector2(_controller.transform.forward.x, _controller.transform.forward.z);// 获取玩家的速度方向,并且进行归一化Vector2 velocityDirection = new Vector2(_controller.velocity.normalized.x, _controller.velocity.normalized.z);// 如果速度为零,返回 0 或者其他默认值,表示没有移动if (velocityDirection.sqrMagnitude == 0f){return Vector2.zero; // 玩家没有移动时,角度为 0(可以自定义)}// 计算面向方向和速度方向之间的夹角float angle = Vector2.SignedAngle(facingDirection, velocityDirection);Quaternion quaternion = Quaternion.Euler(0, 0, angle);return (quaternion * Vector2.up).normalized;
}

计算两个向量的夹角,再按照两个夹角的角度去旋转一个(0, 1)向量。十分简单(也是踩了不少的坑)

这里是有问题的,通过这个获取的向量变化非常快,对于玩家角色而言就是很容易出现角色动画的跳变,因此需要在修改参数时额外进行一次插值,如下

Vector2 direction = GetXYDirectionRelativeControllerRotation();
Vector2 curDirection = new Vector2(_animator.GetFloat(_animIDDirectionX), _animator.GetFloat(_animIDDirectionY));
Vector2 smoothDirection = Vector2.Lerp(curDirection, direction, 10f * Time.deltaTime);
_animator.SetFloat(_animIDDirectionX, smoothDirection.x);
_animator.SetFloat(_animIDDirectionY, smoothDirection.y);

这样就可以获得比较好的方向混合效果了。


空中状态

下面是空中状态的拓扑图

在这里插入图片描述

空中拓扑实际上和官方的跳跃流程是差不多的,只是有两个比较明显的区别

  • 区别一:使用Switch判断是玩家跳跃输入还是玩家悬空导致的进入该状态机
  • 区别二:除Switch是空节点外,其余三个都是基于速度的混合树,用于混合从静止跳跃到奔跑跳跃的动画。

这个就比较常规了,但是因为涉及到不同动画片段的混合,尽量不要使用固定持续时间,尽量使用百分比持续时间,因为动画长短不一,容易导致在一个状态中绕不出去。退出时间也是同理。

分层动画

以上动画都工作在BaseLayer层,我的预期是用作下半身移动和空手时的移动操作。

接下来是WeaponLayer层,即玩家装备物品时会需要的层

这一层使用了AvatarMask进行蒙版,但在使用这玩意儿的时候遇到了个史诗级大坑。Mask的详细面板有两个条目,Humanoid和Transform,按照官方文档的说法,第一个可以大致选定蒙版的区域,手啊,躯干啊,头啊。第二个可以更加细致的调整哪些骨骼会收到影响。

我兴致勃勃的先用Humanoid进行蒙版,嗯,工作的很好。然后调整Transform让WeaponLayer只能影响到躯干的上半身。结果呢,是的,完全没有反应。

上网扒拉半天,得到的结果是:导入的骨骼网格体,如果使用Generic则可以使用Transform,使用Humanoid则可以使用Humanoid。搞了半天这个Mask的两个选项甚至不能同时用,而且和导入的骨骼设置有关。多有意思,我只好把骨骼改成Generic才能使用Transform。并且编辑这个Transform时,对号还得一个一个自己取消,也没个取消父级自动取消子级的。

是的,这就是Unity,随手一做就能发现一个6年前就有人在问的问题。

总之分层是可以工作了,这一层目前还没做多少东西,只是导了个武器和待机动作,更多东西等做出来过几天再发。

在这里插入图片描述

相关文章:

【Unity/Animator动画系统】多层动画状态机实现角色的基本移动

文章目录 前言实现顶层地面状态四方向混合树计算动画所需参数 空中状态分层动画 前言 最近打算做个Rougelike RPG 塔科夫 混搭风格的冒险游戏。暂且就当是一个有随机元素,有基地,死亡会掉落物品的近战塔科夫罢。 花了三天时间,整合了Mixa…...

每日算法一练:剑指offer——栈与队列篇(1)

1.图书整理II 读者来到图书馆排队借还书,图书管理员使用两个书车来完成整理借还书的任务。书车中的书从下往上叠加存放,图书管理员每次只能拿取书车顶部的书。排队的读者会有两种操作: push(bookID):把借阅的书籍还到图书馆。pop…...

【Java】ArrayList与LinkedList详解!!!

目录 一🌞、List 1🍅.什么是List? 2🍅.List中的常用方法 二🌞、ArrayList 1🍍.什么是ArrayList? 2🍍.ArrayList的实例化 3🍍.ArrayList的使用 4🍍.ArrayList的遍…...

怎么用VIM查看UVM源码

利用ctags工具可以建立源码的索引表,在使用VIM或其他文本编辑器时,就可以跳转查看所调用的UVM或VIP的funtcion/task/class等源码了。 首先需要确认ctags安装,一般安装VIM后都有,如果没有可以手动安装。在VIM中可以输入:help ctag…...

数据结构C语言描述3(图文结合)--双链表、循环链表、约瑟夫环问题

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…...

第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令

文章目录 第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令TCP 设备的 READ 命令READ 修改 $ZA 和 $ZB$ZA 和 READ 命令 第二十五章 TCP 客户端 服务器通信 - TCP 设备的 READ 命令 TCP 设备的 READ 命令 从服务器或客户端发出 READ 命令以读取客户端或服务器设置的…...

【C++】哈希表的实现详解

哈希表的实现详解 一、哈希常识1.1、哈希概念1.2、哈希冲突1.3、哈希函数(直接定执 除留余数)1.4、哈希冲突解决闭散列(线性探测 二次探测)开散列 二、闭散列哈希表的模拟实现2.1、框架2.2、哈希节点状态的类2.3、哈希表的扩容2…...

高阶C语言之五:(数据)文件

目录 文件名 文件类型 文件指针 文件的打开和关闭 文件打开模式 文件操作函数(顺序) 0、“流” 1、字符输出函数fputc 2、字符输入函数fgetc 3、字符串输出函数fputs 4、 字符串输入函数fgets 5、格式化输入函数fscanf 6、格式化输出函数fpr…...

服务器上部署并启动 Go 语言框架 **GoZero** 的项目

要在服务器上部署并启动 Go 语言框架 **GoZero** 的项目,下面是一步步的操作指南: ### 1. 安装 Go 语言环境 首先,确保你的服务器上已安装 Go 语言。如果还没有安装,可以通过以下步骤进行安装: #### 1.1 安装 Go 语…...

【Java SE 】继承 与 多态 详解

🔥博客主页🔥:【 坊钰_CSDN博客 】 欢迎各位点赞👍评论✍收藏⭐ 目录 1. 继承 1.1 继承的原因 1.2 继承的概念 1.3 继承的语法 2. 子类访问父类 2.1 子类访问父类成员变量 2.1.1 子类与父类不存在同名成员变量 2.1.2 子类…...

【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法

【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法 目录 文章目录 【大语言模型】ACL2024论文-16 基于地图制图的罗马尼亚自然语言推理语料库的新型课程学习方法目录摘要:研究背景:问题与挑战:如何解…...

秋招大概到此结束了

1、背景 学院本,软工,秋招只有同程,快手和网易面试,后两家kpi(因为面试就很水),秋招情况:哈啰(实习转正ing),同程测开offer。 2、走测开的原因 很…...

华为OD机试真题---字符串化繁为简

华为OD机试真题中的“字符串化繁为简”题目是一个涉及字符串处理和等效关系传递的问题。以下是对该题目的详细解析: 一、题目描述 给定一个输入字符串,字符串只可能由英文字母(a~z、A~Z)和左右小括号((、)&#xff0…...

概念解读|K8s/容器云/裸金属/云原生...这些都有什么区别?

随着容器技术的日渐成熟,不少企业用户都对应用系统开展了容器化改造。而在容器基础架构层面,很多运维人员都更熟悉虚拟化环境,对“容器圈”的各种概念容易混淆:容器就是 Kubernetes 吗?容器云又是什么?容器…...

初识Arkts

创建对象: 类: 类声明引入一个新类型,并定义其字段、方法和构造函数。 定义类后,可以使用关键字new创建实例 可以使用对象字面量创建实例 在以下示例中,定义了Person类,该类具有字段name和surname、构造函…...

基本的SELECT语句

1.SQL概述 SQL(Structured Query Language)是一种用于管理和操作关系数据库的编程语言。它是一种标准化的语言,用于执行各种数据库操作,包括创建、查询、插入、更新和删除数据等。 SQL语言具有简单、易学、高效的特点,…...

51c自动驾驶~合集30

我自己的原文哦~ https://blog.51cto.com/whaosoft/12086789 #跨越微小陷阱,行动更加稳健 目前四足机器人的全球市场上,市场份额最大的是哪个国家的企业?A.美国 B.中国 C.其他 波士顿动力四足机器人 云深处 绝影X30 四足机器人 &#x1f…...

Python Tutor网站调试利器

概述 本文主要是推荐一个网站:Python Tutor. 网站首页写道: Online Compiler, Visual Debugger, and AI Tutor for Python, Java, C, C++, and JavaScript Python Tutor helps you do programming homework assignments in Python, Java, C, C++, and JavaScript. It contai…...

h5小游戏实现获取本机图片

h5小游戏实现获取本机图片 本文使用cocos引擎 1.1 需求 用户通过文件选择框选择图片。将图片内容转换为Cocos Creator的纹理 (cc.Texture2D),将纹理设置到 cc.SpriteFrame 并显示到节点中。 1.2 实现步骤 创建文件输入框用于获取文件 let input document.createElement(&quo…...

前端 javascript a++和++a的区别

前端 javascript a和a的区别 a 是先执行表达式后再自增,执行表达式时使用的是a的原值。a是先自增再执行表达示,执行表达式时使用的是自增后的a。 var a0 console.log(a); // 输出0 console.log(a); // 输出1var a0 console.log(a); // 输出1 console.l…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

微信小程序之bind和catch

这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...