Unreal Engine10:Character的实现

news2024/11/15 19:53:00

写在前面

这里主要是介绍一下Character的实现,顺带也介绍一下UE4资源的获取;

一、UE4资源获取

1. 地图的获取

1.1 下载资源

  • 在Epic Games Launcher的虚幻商城中搜索内容,带有环境标签的就主要是地图资源;
  • 有一些是免费的资源和适用于初学者的资源,而且每个月还会有本月免费资源,所以还是很不错的o( ̄▽ ̄)ブ;
  • 选择资源的时候注意资源的支持的引擎版本要和使用的引擎版本匹配;
  • 这里以太阳神庙项目作为例子(因为它是免费而且适用于UE4.24);
  • 购买项目之后,切换界面到->保管库,刚刚购买的项目就在放在这里;
  • 选择创建项目,就会自动将项目下载到指定的本地位置;

创建项目

  • 创建完成后,在我的工程中双击项目打开即可;

1.2 加载到自己的项目

  • 然后是将太阳神庙项目中需要的地图迁移到自己的项目中;
  • 对内容浏览器Maps文件夹右键->迁移,迁移的路径为自己项目下的Content文件夹;
  • 地图资源通常是放在Content文件夹中的Maps文件夹里面的,所以记得在命名的时候符合规范(参考之前的Unreal Engine05:UE4基本概念一文),这样在迁移之后就不会出现资源的放置混乱;
  • 如果原来有Maps文件夹,就会和之前的地图资源合并放到同一个文件夹中,如果没有则正好可以获得一个Maps文件夹;

1.3 修改默认地图

  • 在Editor主面板中的设置->地图和模式,修改编辑器开始地图游戏默认地图

修改游戏默认地图

2. 角色的获取

1. 下载资源

  • 在Epic Games Launcher的虚幻商城中搜索内容,带有角色标签的就主要是角色资源;
  • 人物建模越精细,则角色资源就越大;
  • 这里用的是动画初学者内容包,是免费的,而且很小;

2. 加载到自己的项目

  • 由于角色资源不是一个完整的项目,所以是添加到工程而不是创建工程

添加到工程

  • 选择自己的项目添加即可,添加后项目的Content文件夹中会增加一个AnimStarterPack文件夹,里面就是刚刚添加的资源;

添加的资源

  • 里面包含了角色的动画、骨架、材质和纹理等资源;

3. 绑定到Character上

  • 用Character的C++类创建一个蓝图类;

创建蓝图类

  • 点击Mesh组件(这个组件是继承自ACharacter的,普通的Pawn并不会默认带有),然后在Mesh->骨架网格体中选择一个角色的骨架即可;

添加骨骼

  • 然后还需要做一些调整:
    • 将骨架移动到胶囊体的中心
    • 调整胶囊体CapsuleComponent的大小以覆盖骨架
  • 调整后如下:

调整后的骨架

二、创建一个Character的C++类

  • 创建的C++类也是放在Source文件夹中的Public和Private文件夹中;
  • 选择Character作为继承的父类;

头文件

  • 仅从头文件来看,Character类和Pawn类的头文件是一样的,并无区别;
  • 但从继承的ACharacter类来看,可以看到比APawn类多了三个组件,如下:

ACharacter类

1. 增加摄像机和弹簧臂

  • 在头文件中加入摄像机和弹簧臂组件;

头文件

  • 在构造函数中初始化弹簧臂和摄像机;
    cpp实现

  • 一些注意的点如下:

    • 将组件的bUsePawnControlRotation设置为true,则该组件将跟随Pawn的控制器进行旋转,也就是将旋转的控制加到Pawn的控制器上即可,无需单独设置弹簧臂的旋转;
    • 弹簧臂需要跟随旋转,摄像机由于是挂载在弹簧臂的插槽上的,所以会自动跟着弹簧臂旋转,无需单独设置;
  • 在生成蓝图类之后一定要在细节面板中的Camera Settings->使用Pawn控制旋转确认弹簧臂和摄像机的使用控制器设置是否和代码的中的一致(因为我发现即使是在C++中写了勾选,但在蓝图类中还是不一致的);

在这里插入图片描述

2. 增加输入控制映射

  • 项目设置->输入中增加Jump、Look_Up和Turn_Right,如下:

输入映射

  • Look_Up实际上就是视角上下移动,但这里不是直接控制摄像机或者弹簧臂了,而是传到Controller;
  • Turn_Right实际上就是视角左右移动,但这里也不是直接控制摄像机或者弹簧臂了,而是传到Controller;

3. 用Controller实现输入控制

  • 由于Pawn可以由Controller控制其运动,因此它运动的控制函数实现最好是都交给Controller,而不是像之前那样直接用Actor的状态实现运动;
  • 在头文件定义响应事件函数,如下:

头文件

  • 实现MoveForward()MoveRight()函数,如下:

函数实现

  • 一些注意的点如下:

    • 这里是使用了控制器的旋转角度分量作为Pawn的前进方向的,而不是像之前那样直接用GetActorRightVector()函数,也就是把运动的控制统一放到了Controller上,而不是直接在Actor上进行;
    • 这样的话,因为控制器的旋转角度就是弹簧臂的旋转角度,也是摄像机的旋转角度,因此实际上就是以摄像机当前的局部坐标系作为Pawn移动的相对方向;
    • 当然,这种写法只能在Pawn及其派生类上用,因为Pawn才能拥有Controller;
    • 推荐是这种写法,它和自定义运动组件(参看:Unreal Engine09:自定义Pawn运动组件一文)并不冲突,因为运动组件的作用是在AddMovementInput()函数中生效的,也就是说只要使用了AddMovementInput()函数,自定义运动组件就能生效;
  • 实现TurnAtRight()TurnLookup()函数,如下:

函数实现

  • 一些注意的点如下:
    • 这里是直接修改了Controller的旋转值,而不是像之前那样,分别用SetActorRotation()修改Actor的旋转值和调用弹簧臂组件的函数修改弹簧臂的旋转值;
    • 也就是把旋转的控制也加到的Controller上,然后弹簧臂跟随Controller旋转
    • 也推荐是这种写法,相当于是将控制全部交给Controller;
    • 特别注意:
      • 这里用了速率来控制旋转的快慢,也就是AddControllerPitchInput()增加的旋转角度等于旋转速率乘以两帧之间的时间,相当于是之前在Tick()中实现的逻辑,只不过这里没有了DeltaTime作为传入的参数;
      • TurnLookup()函数中,传入AddControllerPitchInput()的参数是-Value,这是因为鼠标上推是Y值为正,但实际上控制器(也就是弹簧臂,因为弹簧臂旋转的角度和控制器相同)应该向下旋转视角才能向上看,所以刚好是和传入值是相反的;

4. 绑定输入到响应事件函数

  • SetupPlayerInputComponent中绑定映射,如下:

函数实现

  • 一些注意的点如下:
    • 这里第一次实现了操作映射,需要绑定两个响应事件函数,一个是按下按钮时执行,一个是抬起按钮时执行;
    • 跳起动作直接是调用了ACharacter的自带函数,因为这个动作输入既不会导致视角的旋转,也不会导致Character位置的移动,所以可能实现上没有那么多的花里胡哨;

5. 其他的一些动作控制设置

  • 在构造函数里面还需要再设置一些变量,如下:
    函数实现

三、动画蓝图

  • 动画蓝图用于让Character在运动过程中使用动画;

1. 新建一个动画实例C++类

  • 创建的C++类也是放在Source文件夹中的Public和Private文件夹中;
  • 选择AnimInstance作为继承的父类;

新建类

  • 此时的头文件和.cpp是空的,没有其他的内容,如下:

头文件

  • 这个动画实例类主要是用来获取Pawn的一些当前状态,这样在后续的动画控制中才能够根据Pawn的状态执行不同的动画;

1. 头文件

  • 头文件的实现如下:

头文件

  • 在头文件中增加两个记录Pawn状态的向量,一个是Pawn当前的速度,一个是Pawn是否跳起腾空
  • Pawn指针指向当前动画作用的Pawn类对象,也就是说动画不能脱离角色来进行实现(这在逻辑上很合理);
  • NativeInitializeAnimation()是动画的初始化函数,相当于是构造函数的功能;
  • UpdateAnimationProperties()是用于获取Pawn的运动状态并绑定到当前类属性中;

2. cpp实现

  • 实现初始化函数如下:

函数实现

  • 实现的UpdateAnimationProperties()函数如下:

函数实现

2. 新建一个动画蓝图类

  • 这里并不是直接用C++类派生一个蓝图类的,而是需要先创建更高级一点的蓝图类;
  • 新建一个Animations文件夹;
  • 在内容浏览器中右键动画->动画蓝图,创建动画蓝图:

创建动画蓝图

  • 选择AnimInstance作为父类目标骨架则选择Character对应的骨架资源;

创建动画蓝图

  • 这样该动画就能够和骨骼资源绑定在一起了;
  • 打开该动画蓝图,选择类设置->类选项->父类,设置为刚刚创建的动画实例类UManAnimInstance

2.1 新建一维混合空间动画

  • 在内容浏览器中右键动画->混合空间1D新建一个一维混合空间动画;
    一维混合空间动画

  • 在动画界面编辑一维混合空间动画的结果如下:

编辑一维混合动画

  • 一些注意的点如下:
    • 界面右下方是动画资源浏览器,和当前骨骼有关的动画都已经在这里面了;
      • 绿色图标的代表动画序列,可以看做是最基本的动画资源;
      • 橙色图标的代表混合空间,可以看做是多个动画序列的叠加和组合而成的动画资源;
      • 双击动画资源可以在界面中预览和修改对应的动画;
    • 在界面下方是一维动画轴(这也是一维混合空间的命名由来),可以在轴上的不同位置放置已有的动画作为关键帧,从而生成组合动画;
      • 绿色菱形点是当前预览窗口显示的动画效果;
      • 白色菱形点是动画关键帧,通常起码一头一尾是要有一个关键帧的;
    • 界面左方的资源详情中可以修改一维动画轴的一些设置;
      • 修改名称可以为一维动画轴命名;
      • 修改最小轴值最大轴值可以修改轴的定义域;
      • 增加网格分区数量可以增加轴上可以插入关键帧的位置;
      • 修改内插类型可以调整关键帧之间的过渡动画生成效果;
    • 这里在0.0处使用Idle_Rifle_Hit动画资源表示站立,在20.0处使用Walk_Fwd_Rifle_Ironsights动画资源表示行走,在100.0处使用Jog_Fwd_Rifle表示慢跑;
    • 这样就完成了一维混合空间动画的制作;

2.2 新建二维混合空间动画

  • 在内容浏览器中右键动画->混合空间新建一个一维混合空间动画;

新建二维混合空间

  • 在动画界面编辑二维混合空间动画的结果如下:

编辑二维混合空间动画

  • 一些注意的点如下:
    • 在界面下方是二维动画轴(这也是二维混合空间的命名由来),可以在轴上的不同位置放置已有的动画作为关键帧,从而生成组合动画;
      • 绿色菱形点是当前预览窗口显示的动画效果;
      • 白色菱形点是动画关键帧,通常起码每条最外面的边上是要有一个关键帧的;
    • 界面左方的资源详情中可以修改一维动画轴的一些设置;
      • 修改名称可以为一维动画轴命名;
      • 修改最小轴值最大轴值可以修改轴的定义域;
      • 增加网格分区数量可以增加轴上可以插入关键帧的位置;
      • 修改内插类型可以调整关键帧之间的过渡动画生成效果;
    • 这里将水平坐标命名为Direction,范围是[-180, 180],垂直坐标命名为Speed,范围是[0, 100];
    • 关键帧还是用之前一维动画轴用过的站、走、跑三种动画,但走和跑用到了默认实现的向前、向左、向右和向后四种动画,-90用的是向左,90用的是向右,-180180用的都是向后,0用的是向前,具体的动画序列如下:

动画序列

  • 这样就完成了二维混合空间动画的制作;

2.3 编写蓝图

  • 在动画蓝图中的事件图表窗口中编写蓝图逻辑;
  • 这里只需要每帧调用C++中实现的UpdateAnimationProperties()函数获取Pawn的状态即可;
    蓝图

2.4 编写动画图表

  • 添加一个状态机,命名为“Man State Machine”,如下:

状态机

  • 编写状态机,每个状态可以视为一个动画,不同状态有对应的跳转逻辑,如下:

状态机实现

  • 下面介绍每个状态和跳转逻辑的蓝图实现;
  • (1) Stand_Walk_Run状态:
    • 通过C++定义的MovementSpeed来控制实现站->走->跑三种动画,用的是刚刚创建的一维混合空间动画;
    • 这里的一维混合空间动画的Speed输入就是刚刚在动画里面的一维动画轴的横坐标

状态实现

  • (2) 转到Jump的逻辑:
  • 用C++定义的IsJumping来控制跳转,这里最终输出的是一个布尔结果;

逻辑实现

  • (3) Jump的状态:
  • 直接用已有的动画序列即可;

状态实现

  • (4) 跳转到In_Air的逻辑:
    • 这里用到了一个 剩余时间(比率) 的函数,也就是前一个状态的动画播放到20%的时候就转到下一个状态;
    • 但其实腾空的状态完全可以不要,这里只是为了演示复杂状态机对动画的控制而已;

状态实现

  • (5) In_Air的状态:
  • 这里用了正向行走作为腾空动画,因为动画资源中并没有腾空的动画;

状态实现

  • (6) 转到On_Floor的逻辑:
  • IsJumping为假即落地;

状态实现

  • (7) On_Floor的状态:
  • 这里仅用Jump_From_Stand动画序列的0.676s后的动画,可以在细节面板中的Settings->初始位置中设置,而且要取消循环动画的勾选;

状态实现

  • (8) 转到Stand_Walk_Run的逻辑:
  • 前一个状态的动画放完了就可以跳转到初始状态;

逻辑实现

  • 另外,可以将Character的运动动画和状态机对应来调试,在当前面板点击播放,然后按照下面选择Character的对应对象即可;

调试状态机

3. 在Character中使用该动画蓝图

  • 在Character蓝图类中选中Mesh组件,在细节面板的Animation->动画模式中选择使用动画蓝图,在动画类中选择刚刚创建的动画蓝图类;

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

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

相关文章

C#--耗时操作实现UI界面实时更新不阻塞(耗时操作解决窗体卡顿)

前言C#实现窗体加载进度条或者百分比实时显示耗时操作的进度,方法有很多。但是经过我的学习、查找与实际应用,发现Task配合MethodInvoker最为高效便捷。下面我就来结合代码讲一下要注意的问题。基础知识C#在winform上进行耗时操作往往会放置progressbar&…

JavaWeb 实战 01 - 计算机是如何工作的

计算机是如何工作的1. 计算机发展史2. 计算机的基本组成2.1 冯诺依曼体系结构2.2 CPU的内部结构2.3 指令2.3.1 指令表2.3.1.1 寄存器2.3.2 CPU的工作流程2.4 小结3. 操作系统3.1 核心功能3.2 操作系统的软硬件结构3.3 什么是进程 / 任务3.4 进程管理3.4.1 管理3.4.2 PCB : 进程…

Carl2——二叉树

一.定义struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {} };二.遍历深度优先1.1 迭代法【1】前序遍历&#xff08;144&#xff09;class Solution { public:vector<int> preorderTraversal(TreeNode* roo…

小文智能结合ChatGPT的产业未来

最近几个月&#xff0c;由人工智能实验室OpenAI发布的对话式大型语言模型ChatGPT在国内外各大平台掀起了一阵AI狂潮。短短几天时间&#xff0c;其用户量就突破了百万大关&#xff0c;注册用户之多一度导致服务器爆满。 继AI画图之后&#xff0c;ChatGPT成为了新的顶流&#xf…

支付宝二面:使用 try-catch 捕获异常会影响性能吗?

一. JVM异常处理逻辑 Java 程序中显式抛出异常由athrow指令支持&#xff0c;除了通过 throw 主动抛出异常外&#xff0c;JVM规范中还规定了许多运行时异常会在检测到异常状况时自动抛出(效果等同athrow), 例如除数为0时就会自动抛出异常&#xff0c;以及大名鼎鼎的 NullPointe…

论文阅读:NeRF++: ANALYZING AND IMPROVING NEURAL RADIANCE FIELDS

中文标题&#xff1a;分析并提升神经辐射场 提出问题 把NeRF生成的视角图像投影到一个球模型上&#xff08;体密度在球面上为1&#xff0c;其余为零&#xff09;&#xff0c;这个模型可以很好解释训练集&#xff08;左2&#xff09;&#xff0c;但是一旦推广到其他视角&#x…

阶段八:服务框架高级(第五章:服务异步通信-高级篇(RabbitMQ高级))

阶段八&#xff1a;服务框架高级&#xff08;第五章&#xff1a;服务异步通信-高级篇&#xff08;RabbitMQ高级&#xff09;&#xff09;Day-第五章&#xff1a;服务异步通信-高级篇&#xff08;RabbitMQ高级&#xff09;0.学习目标1.消息可靠性1.1.生产者消息确认1.1.1.修改配…

Docker离线部署

Docker离线部署 目录 1、需求说明 2、下载docker安装包 3、上传docker安装包 4、解压docker安装包 5、解压的docker文件夹全部移动至/usr/bin目录 6、将docker注册为系统服务 7、重启生效 8、设置开机自启 9、查看docker版本信息 1、需求说明 大部份公司为了服务安全…

【PostgreSQL的idle in transaction连接状态】

在平时查询pg_stat_activity这个视图的时候&#xff0c;每一行包含了一个进程的相关信息&#xff0c;包含当前正在执行的SQL&#xff0c;或者会话的状态等等&#xff0c;state字段表示当前进程的状态。在PostgreSQL数据库里&#xff0c;其实代码里总共定义了7种BackendState&am…

手推式洗地机什么牌子好?洗地机品牌排行榜

当今潮流下&#xff0c;大家都开始纷纷追求高品质的居家生活&#xff0c;洗地机也成为越来越多人的追求&#xff0c;因为和传统的吸尘器相比&#xff0c;洗地机除了有扫地的功能之外&#xff0c;还可以轻松搞定家里的拖地任务&#xff0c;下面我们一起来看看洗地机排行榜都有哪…

怎么把音乐传到苹果手机上?如何将铃声导入iphone

很多人肯定都有这样的经验—比起电脑&#xff0c;使用iPhone和iPad播放音乐能获得更好的声音体验。 因此&#xff0c;现在有越来越多的用户将音乐传输到iPhone/iPad上播放。怎么把音乐传到苹果手机上&#xff1f;把音乐导入苹果手机&#xff0c;主要有2种方法&#xff1a;一种是…

【python】运算符,有关它的一切,都在这里了

Python运算符嗨害大家好鸭&#xff01;我是小熊猫~什么是运算符&#xff1f;Python算术运算符Python比较运算符Python赋值运算符Python位运算符Python逻辑运算符Python成员运算符Python身份运算符Python运算符优先级嗨害大家好鸭&#xff01;我是小熊猫~ 源码资料电子书:点击此…

【软考——系统架构师】UML 建模与架构文档化

&#x1f50e;这里是【软考——系统架构师】&#xff0c;关注我考试轻松过线 &#x1f44d;如果对你有帮助&#xff0c;给博主一个免费的点赞以示鼓励 欢迎各位&#x1f50e;点赞&#x1f44d;评论收藏⭐️ 文章目录UML 基础UML 软件开发过程系统架构文档化送书福利UML 基础 U…

【2.27】动态规划、MySQL锁,基础篇、Redis

执行一条 select 语句&#xff0c;期间发生了什么&#xff1f; MySQL 执行流程是怎样的&#xff1f; MySQL 的架构共分为两层&#xff1a;Server 层和存储引擎层。 Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在这实现&#xff0c;主要包括连接器&…

MyBatis - 07 - MyBatis的各种查询功能

文章目录项目 结构SelectMapper接口SelectMapper.xmlSelectMapperTest测试类测试结果1、查询一个实体类对象&#xff08;1.根据id查询用户信息&#xff09;2、查询一个list集合&#xff08;2.查询所有用户信息&#xff09;3、查询单个数据&#xff08;3.查询用户信息的总记录数…

Datawhale统计学习方法打卡Task05

学习教材《统计学习方法&#xff08;第二版&#xff09;》李航 学习内容&#xff1a;第5章 决策树 第五章 决策树 决策树是一种基本你的分类与回归方法。决策树模型呈树形结构&#xff0c;在分类问题中&#xff0c;表示基于特征对实例进行分类的过程。通过ID3和C4.5介绍特征…

测试开发工程师,年薪100W不过分吧

在说测试开发工程师的薪资待遇之前&#xff0c;咱们要先了解软件测试岗位是用来做什么的&#xff0c;岗位是否重要&#xff0c;只有你知道了这些&#xff0c;才能判断这个岗位是否有价值&#xff01;软件测试是依据需求分析和测试用例&#xff0c;运用手工和自动化的手段来验证…

mysql中用逗号隔开的字段作查询用(find_in_set的使用)

mysql中用逗号隔开的字段作查询用(find_in_set的使用) 场景说明 在工作中&#xff0c;经常会遇到一对多的关系。想要在mysql中保存这种关系&#xff0c;一般有两种方式&#xff0c;一种是建立一张中间表&#xff0c;这样一条id就会存在多条记录。或者采用第二种方式&#xff…

[音视频] wav 格式

wav 格式结构 WAV文件遵循RIFF规则&#xff0c;其内容以区块&#xff08;chunk&#xff09;为最小单位进行存储。WAV文件一般由3个区块组成&#xff1a;RIFF chunk、Format chunk和Data chunk。另外&#xff0c;文件中还可能包含一些可选的区块&#xff0c;如&#xff1a;Fact…

javascript尾递归优化

JS中的递归 我们来看一个阶乘的代码 function foo( n ){if(n < 1){return 1;}return n * foo( n - 1 ); }foo(5); // 120下面分析一下&#xff0c;代码运行过程中,执行上下文栈是怎么变化的 这个代码是在全局作用域中执行的&#xff0c;所以在foo函数得到执行之前&#x…