原文:
annas-archive.org/md5/697adf25bb6fdefd7e5915903f33de14
译者:飞龙
前言
关于本书
游戏开发既可以是一种创造性的兴趣爱好,也可以是一种全职职业道路。这也是提高你的 C++技能并将其应用于引人入胜和具有挑战性的项目的一种激动人心的方式。
《使用虚幻引擎进行游戏开发项目》从你作为游戏开发者需要开始的基本技能开始。游戏设计的基础将被清晰地解释,并通过现实练习进行实际演示。然后,你将通过具有挑战性的活动应用所学到的知识。
这本书从虚幻编辑器和关键概念开始,如角色、蓝图、动画、继承和玩家输入。然后,你将开始三个项目中的第一个:构建一个躲避球游戏。在这个项目中,你将探索线追踪、碰撞、抛射物、用户界面和音效,结合这些概念来展示你的新技能。
然后,你将开始第二个项目;一个横向卷轴游戏,你将实现包括动画混合、敌人人工智能、生成对象和可收集物品在内的概念。最后一个项目是一款 FPS 游戏,你将涵盖创建多人环境的关键概念。
通过本书,你将拥有信心和知识,开始自己的创意 UE4 项目,并将你的想法变为现实。
关于作者
Hammad Fozi是 BIG IMMERSIVE 的首席游戏开发者(虚幻引擎)。
Gonçalo Marques从 6 岁开始就是一名活跃的玩家。他曾在葡萄牙初创公司 Sensei Tech 担任自由职业者,在那里他使用 UE4 开发了一个内部系统,用于生成辅助机器学习的数据集。
David Pereira在 1998 年开始了他的游戏开发生涯,他学会了使用 Clickteam 的 The Games Factory,并开始制作自己的小游戏。David 要感谢以下人员:我要感谢我的女朋友,我的家人和我的朋友在这个旅程中对我的支持。这本书献给我的祖母特蕾莎(“E vai daí ós’pois…!”)。
Devin Sherry是一名技术设计师,就职于名为 People Can Fly 的游戏工作室,并参与了他们使用虚幻引擎 4 构建的最新 IP。Devin 在 2012 年在前进科技大学学习游戏开发和游戏设计,获得了游戏设计学士学位。
受众
这本书适合任何想要开始使用 UE4 进行游戏开发的人。它也适用于以前使用过虚幻引擎并希望巩固、改进和应用他们的技能的人。为了更好地理解本书中解释的概念,你必须具备 C++基础知识,并了解变量、函数、类、多态和指针。为了与本书中使用的 IDE 完全兼容,建议使用 Windows 系统。
关于章节
《第一章》,《虚幻引擎介绍》,探讨了虚幻引擎编辑器。你将被介绍到编辑器的界面,看到如何在关卡中操作角色,了解蓝图视觉脚本语言的基础,并发现如何创建可以被网格使用的材质资产。
《第二章》,《使用虚幻引擎》,介绍了虚幻引擎游戏基础知识,以及如何创建一个 C++项目和设置项目的内容文件夹。你还将介绍动画的主题。
《第三章》,《角色类组件和蓝图设置》,向你介绍了虚幻角色类,以及对象继承的概念以及如何使用输入映射。
《第四章》,《玩家输入》,介绍了玩家输入的主题。你将学习如何将按键或触摸输入与游戏内动作(如跳跃或移动)相关联,通过使用动作映射和轴映射。
第五章,“线性跟踪”,开始了一个名为 Dodgeball 的新项目。在本章中,您将了解线性跟踪的概念以及它们在游戏中的各种用途。
第六章,“碰撞对象”,探讨了对象碰撞的主题。您将了解碰撞组件、碰撞事件和物理模拟。您还将学习定时器、投射物移动组件和物理材料的主题。
第七章,“UE4 实用工具”,教您如何在虚幻引擎中实现一些有用的实用工具,包括角色组件、接口和蓝图函数库,这将有助于使您的项目结构良好,并且易于其他加入您团队的人理解。
第八章,“用户界面”,探讨了游戏 UI 的主题。您将学习如何使用虚幻引擎的 UI 系统 UMG 制作菜单和 HUD,以及如何使用进度条显示玩家角色的生命值。
第九章,“音频-视觉元素”,介绍了虚幻引擎中声音和粒子效果的主题。您将学习如何将声音文件导入项目并将其用作 2D 和 3D 声音,以及如何将现有的粒子系统添加到游戏中。最后,将制作一个新的关卡,使用前几章构建的所有游戏机制来完成 Dodgeball 项目。
第十章,“创建一个 SuperSideScroller 游戏”,分解了 SuperSideScroller 游戏项目的游戏机制。您将通过 Epic Games Launcher 创建 C++ SideScroller 项目模板,并通过操纵默认人体模型骨架和导入自定义骨骼网格来学习动画的基本概念。
第十一章,“混合空间 1D、按键绑定和状态机”,向您介绍了用于开发平滑动画混合的工具,包括混合空间 1D 和动画状态机。您还将进入 C++代码,通过按键绑定和角色移动组件的帮助来开发玩家角色的奔跑机制。
第十二章,“动画混合和蒙太奇”,向您介绍了动画蒙太奇和动画蓝图中的动画混合功能,以开发玩家角色的投掷动画。您将了解动画插槽,并使用每个骨骼的分层混合来正确地在角色的移动动画和投掷动画之间进行混合。
第十三章,“敌人人工智能”,涵盖了人工智能以及如何使用行为树和黑板开发人工智能。您将实现一个沿着自定义路径巡逻的人工智能,使用您将开发的蓝图角色。
第十四章,“生成玩家投射物”,向您介绍了动画通知以及如何在游戏世界中生成对象。您将实现一个自定义的动画通知,在特定帧生成玩家投射物的投掷动画。您还将开发玩家投射物的功能,使其能够摧毁敌人人工智能。
第十五章,“收集品、能量增强和拾取物”,演示了如何创建一个可以操纵玩家移动的自定义药水增强,以及玩家角色的可收集硬币。您还将通过开发一个简单的 UI 来学习更多关于 UMG,以便统计玩家找到的收集品数量。
第十六章,“多人游戏基础”,向您介绍了重要的多人游戏概念,如服务器-客户端架构、连接、角色所有权、角色和变量复制。您还将学习如何制作 2D 混合空间以及如何使用变换修改骨骼节点。您将开始通过创建一个角色来工作在一个多人游戏 FPS 项目上,该角色可以行走、跳跃、上下查看,并具有两个复制的状态:生命值和护甲。
第十七章“远程过程调用”介绍了远程过程调用的使用方法,以及如何在虚幻引擎 4 中使用枚举和双向循环数组索引。您还将通过添加武器和弹药的概念来扩展多人游戏 FPS 项目。
第十八章“多人游戏中的游戏框架类”是本书的最后一章,解释了多人游戏中游戏框架类的存在位置,如何使用游戏状态和玩家状态类,以及如何实现一些有用的内置功能。您还将了解如何在游戏模式中使用匹配状态和其他概念。最后,您将通过添加死亡、重生、记分牌、击杀限制和拾取物品的概念来完成多人游戏 FPS 项目。
约定
文本中的代码单词、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL 和用户输入显示如下:
“打开Project Settings
并转到Engine
部分内的Collision
子部分。”
屏幕上显示的文字,例如菜单或对话框中的文字,也会在文本中出现,如下所示:
“点击New Object Channel
按钮,命名为Dodgeball
,并将其Default Response
设置为Block
。”
代码块设置如下:
if (bCanSeePlayer)
{
//Start throwing dodgeballs
GetWorldTimerManager().SetTimer(ThrowTimerHandle,this, &AEnemyCharacter::ThrowDodgeball,ThrowingInterval,true, ThrowingDelay);
}
新术语、缩写和重要单词显示如下:“在本章中,我们将介绍远程过程调用(RPC),这是另一个重要的多人游戏概念,允许服务器在客户端上执行函数,反之亦然。”
开始之前
本节将指导您完成安装和配置步骤,以便为您设置必要的工作环境。
安装 Visual Studio
因为我们将在虚幻引擎 4 中使用 C++,所以我们需要一个与引擎轻松配合的IDE(集成开发环境)。Visual Studio Community 是 Windows 上可用于此目的的最佳 IDE。如果您使用 macOS 或 Linux,您将需要使用另一个 IDE,例如 Visual Studio Code、QT Creator 或 Xcode(仅在 macOS 上可用)。
本书中给出的指导是针对 Windows 上的 Visual Studio Community 的,因此,如果您使用不同的操作系统和/或 IDE,则需要自行研究如何设置这些内容以在您的工作环境中使用。在本节中,您将通过安装 Visual Studio 来完成,以便您可以轻松编辑 UE4 的 C++文件。
-
转到 Visual Studio 下载网页
visualstudio.microsoft.com/downloads
。我们将在本书中使用的虚幻引擎 4 版本(4.24.3)推荐使用 Visual Studio Community 2019 版本。请务必下载该版本。 -
当您这样做时,打开您刚下载的可执行文件。它最终会带您到以下窗口,您将能够选择您的 Visual Studio 安装的模块。在那里,您将需要选中
Game Development with C++
模块,然后点击窗口右下角的Install
按钮。点击该按钮后,Visual Studio 将开始下载和安装。安装完成后,可能会要求您重新启动计算机。重新启动计算机后,Visual Studio 应该已安装并准备就绪。 -
第一次运行 Visual Studio 时,您可能会看到一些窗口,其中第一个是登录窗口。如果您有 Microsoft Outlook/Hotmail 帐户,您应该使用该帐户登录,否则,您可以点击
Not now, maybe later
跳过登录。
注意
如果您不输入电子邮件地址,您只能在 Visual Studio 锁定之前使用 30 天,之后您必须输入电子邮件地址才能继续使用它。
- 之后,您将被要求选择一个颜色方案。
Dark
主题是最受欢迎的主题,也是我们在本节中将使用的主题。
最后,您可以选择“启动 Visual Studio”选项。然而,一旦您这样做,您可以再次关闭它。我们将在本书的第一章中更深入地了解如何使用 Visual Studio。
Epic Games Launcher
要访问虚幻引擎 4,您需要下载 Epic Games Launcher,可在此链接下载:www.unrealengine.com/get-now
。这个链接将允许您下载 Windows 和 macOS 的 Epic Games Launcher。如果您使用 Linux,您将需要下载虚幻引擎源代码并从源代码编译 - docs.unrealengine.com/en-US/GettingStarted/DownloadingUnrealEngine
:
-
在那里,您需要选择“发布许可证”选项,并点击下面的“选择”按钮。这个许可证将允许您使用 UE4 创建项目,您可以直接发布给您的用户(例如在数字游戏商店)。然而,“创作者许可证”将不允许您直接将您的作品发布给最终用户。
-
之后,您将被要求接受条款和条件,一旦您接受了这些条款,一个.msi 文件将被下载到您的计算机上。下载完成后,打开这个.msi 文件,这将提示您安装 Epic Games Launcher。按照安装说明进行安装,然后启动 Epic Games Launcher。这样做后,您应该会看到一个登录界面。
-
如果您已经有一个帐户,您可以使用现有的凭据直接登录。如果没有,您将需要通过点击底部的“注册”文本来注册 Epic Games 帐户。
登录您的帐户后,您应该会看到“主页”选项卡。从那里,您可以点击“虚幻引擎”文本,转到“虚幻引擎”选项卡。
- 当您完成这些操作后,您将会看到“虚幻引擎”选项卡。虚幻引擎选项卡充当虚幻引擎资源的中心。从这个页面,您将能够访问以下内容:
-
“新闻”页面,您将能够查看所有最新的虚幻引擎新闻。
-
Youtube
频道,您将能够观看数十个关于不同虚幻引擎主题的教程和直播。 -
AnswerHub
页面,您将能够看到、提出和回答虚幻引擎社区提出和回答的问题。 -
“论坛”页面,您将能够访问虚幻引擎论坛。
-
“路线图”页面,您将能够访问虚幻引擎路线图,包括引擎过去版本中提供的功能,以及当前正在开发的未来版本的功能。
-
在 Epic Games Launcher 的顶部,在“虚幻引擎”选项卡中,您将能够看到其他几个选项卡,例如“虚幻引擎”选项卡(您当前正在查看的子选项卡)、“学习”选项卡和“市场”选项卡。让我们来看看这些虚幻引擎子选项卡。
-
“学习”选项卡将允许您访问与学习如何使用虚幻引擎 4 相关的几个资源。从这里,您可以访问“开始使用虚幻引擎 4”页面,该页面将带您进入一个页面,让您选择如何开始学习虚幻引擎 4。
-
您还可以访问“文档”页面,其中包含引擎源代码中使用的类的参考,以及“虚幻在线学习”页面,其中包含有关虚幻引擎 4 特定主题的多个课程。
-
在“学习”选项卡的右侧是“市场”选项卡。该选项卡显示了由虚幻引擎社区成员制作的几个资产和代码插件。在这里,您将能够找到 3D 资产、音乐、关卡和代码插件,这些将帮助您推进和加速游戏的开发。
-
最后,在
Marketplace
标签的右侧,我们有Library
标签。在这里,您将能够浏览和管理所有虚幻引擎版本的安装、您的虚幻引擎项目以及您的市场资产库。因为我们还没有这些东西,所以这些部分都是空的。让我们改变这一点。 -
点击
ENGINE VERSIONS
文本右侧的黄色加号。这将会显示一个新的图标,您将能够选择您想要的虚幻引擎版本。 -
在本书中,我们将使用虚幻引擎的版本
4.24.3
。选择该版本后,点击安装
按钮:
图 0.1:允许你安装虚幻引擎 4.24.3 的图标
- 完成后,您将能够选择此虚幻引擎版本的安装目录,这将是您选择的,然后您应该再次点击
安装
按钮。
注意
如果你在安装 4.24 版本时遇到问题,请确保将其安装在 D 驱动器上,路径尽可能短(也就是说,不要尝试安装太多文件夹深度,并确保这些文件夹名称较短)。
- 这将导致虚幻引擎 4.24.3 的安装开始。安装完成后,您可以通过点击版本图标的
启动
按钮来启动编辑器:
图 0.2:安装完成后的版本图标
代码包
你可以在 GitHub 上找到本书的代码文件,网址为packt.live/38urh8v
。在这里,你将找到练习代码、活动解决方案、图片以及完成本书实际部分所需的任何其他资产,如数据集。
第一章:1.虚幻引擎介绍
概述
本章将是对虚幻引擎编辑器的介绍。您将了解编辑器的界面;如何在关卡中添加、移除和操作对象;如何使用虚幻引擎的蓝图可视化脚本语言;以及如何将材质与网格结合使用。
在本章结束时,您将能够浏览虚幻引擎编辑器,创建自己的角色,操纵它们在关卡中,并创建材质。
介绍
欢迎来到使用虚幻引擎进行游戏开发项目。如果这是您第一次使用虚幻引擎 4(UE4),本书将帮助您开始使用市场上最受欢迎的游戏引擎之一。您将了解如何建立您的游戏开发技能,以及如何通过创建自己的视频游戏来表达自己。如果您已经尝试过使用 UE4,本书将帮助您进一步发展您的知识和技能,以便更轻松、更有效地制作游戏。
游戏引擎是一种软件应用程序,允许您从头开始制作视频游戏。它们的功能集有很大的差异,但通常允许您导入多媒体文件,如 3D 模型、图像、音频和视频,并通过编程来操作这些文件,您可以使用 C++、Python、Lua 等编程语言。
虚幻引擎 4 使用两种主要的编程语言,C++和蓝图,后者是一种可视化脚本语言,允许您做大部分 C++也可以做的事情。虽然本书将教授一些蓝图知识,但我们将主要关注 C++,因此希望您对这种语言有基本的了解,包括变量、函数、类、继承和多态等主题。我们会在适当的时候在本书中提醒您这些主题。
使用虚幻引擎 4 制作的热门视频游戏示例包括堡垒之夜、最终幻想 7 重制版、无主之地 3、星球大战:绝地陨落、战争机器 5和海盗之海,还有许多其他游戏。所有这些游戏都具有非常高的视觉保真度,广为人知,并且拥有或曾经拥有数百万玩家。
在以下链接中,您可以看到一些使用虚幻引擎 4 制作的优秀游戏:www.youtube.com/watch?v=lrPc2L0rfN4
。这个展示将向您展示虚幻引擎 4 允许您制作的游戏的多样性,无论是在视觉还是游戏风格上。
如果您希望有朝一日制作像视频中展示的游戏,或以任何方式为其做出贡献,您已迈出了那个方向的第一步。
我们现在将开始这第一步,我们将开始学习虚幻引擎编辑器。我们将了解其界面,如何在关卡中操纵对象,如何创建我们自己的对象,如何使用蓝图脚本语言,以及主要游戏事件的作用,以及如何为网格创建材质。
让我们从学习如何在这个第一个练习中创建一个新的虚幻引擎 4 项目开始这一章。
注意
在继续本章之前,请确保您已安装了前言中提到的所有必要软件。
练习 1.01:创建一个虚幻引擎 4 项目
在这个第一个练习中,我们将学习如何创建一个新的虚幻引擎 4 项目。UE4 有预定义的项目模板,允许您为项目实现基本设置。在这个练习中,我们将使用第三人称
模板项目。
以下步骤将帮助您完成这个练习:
-
安装虚幻引擎 4.24 版本后,通过点击版本图标的
启动
按钮来启动编辑器。 -
完成以上步骤后,您将会看到引擎的项目窗口,其中将显示您可以打开和处理的现有项目,并且还可以选择创建新项目。因为我们还没有项目,所以“最近的项目”部分将是空的。要创建新项目,您首先必须选择“项目类别”,在我们的情况下将是“游戏”。
-
选择了该选项后,点击“下一步”按钮。之后,您将看到项目模板窗口。该窗口将显示 Unreal Engine 中所有可用的项目模板。在创建新项目时,您可以选择添加一些资产和代码,而不是让项目从空白开始,然后您可以根据自己的喜好进行修改。有几种不同类型游戏的项目模板可供选择,但在这种情况下,我们将选择“第三人称”项目模板。
-
选择该模板并点击“下一步”按钮,这将带您到“项目设置”窗口。
在此窗口中,您可以选择与项目相关的一些选项:
-
“蓝图或 C++”:选择是否要能够添加 C++类。默认选项可能是“蓝图”,但在我们的情况下,我们将选择
C++
选项。 -
“质量”:选择您希望项目具有高质量图形还是高性能。您可以将此选项设置为“最高质量”。
-
“光线追踪”:选择是否启用光线追踪。光线追踪是一种新颖的图形渲染技术,它允许您通过模拟光线在数字环境中的路径(使用光线)来渲染物体。尽管这种技术在性能方面相当昂贵,但在照明方面尤其提供了更加逼真的图形。您可以将其设置为“禁用”。
-
“目标平台”:选择您希望该项目运行的主要平台。将此选项设置为“桌面/游戏机”。
-
“入门内容”:选择是否希望该项目附带一组基本资产。将此选项设置为“带入门内容”。
-
“位置和名称”:在窗口底部,您可以选择项目在计算机上存储的位置和名称。
- 确保所有选项都设置为预期值后,点击“创建项目”按钮。这将根据您设置的参数创建项目,并可能需要几分钟才能准备好。
现在让我们通过执行下一节中的步骤来开始学习 Unreal Engine 4 的基础知识,我们将学习如何使用编辑器的一些基础知识。
了解 Unreal
现在您将被介绍 Unreal Engine 编辑器,这是一个非常重要的主题,让您熟悉 Unreal Engine 4。
当您的项目生成完成后,您应该会看到 Unreal Engine 编辑器会自动打开。这个屏幕可能是您在使用 Unreal Engine 时最常见的屏幕,因此熟悉它非常重要。
让我们来分解一下编辑器窗口中所看到的内容:
图 1.1:Unreal Engine 编辑器分为六个主要窗口
内容浏览器
:占据屏幕底部大部分的窗口是内容浏览器
。此窗口将让您浏览和操作项目文件夹中的所有文件和资产。正如在本章开头提到的,虚幻引擎将允许您导入多种多媒体文件类型,而内容浏览器
是将允许您在其各自的子编辑器中浏览和编辑它们的窗口。每当您创建一个虚幻引擎项目时,它都会生成一个内容
文件夹。这个文件夹将是内容浏览器
,这意味着您只能浏览该文件夹中的文件。您可以通过查看其顶部来查看您当前在内容浏览器
中浏览的目录,而在我们的情况下,它是内容 -> ThirdPersonCPP
。
如果您单击内容浏览器
最左侧的过滤器
按钮左侧的图标,您将能够看到内容
文件夹的目录层次结构。此目录视图允许您选择、展开和折叠项目的内容
文件夹中的单个目录:
图 1.2:内容浏览器的目录视图
-
视口
:在屏幕的正中央,您将能够看到视口
窗口。这将显示当前级别的内容,并允许您浏览级别以及在其中添加、移动、删除和编辑对象。它还包含有关视觉过滤器、对象过滤器(您可以看到哪些对象)和级别中的照明的几个不同参数。 -
世界大纲
:在屏幕的右上角,您将看到世界大纲
。这将允许您快速列出和操作在您的级别中的对象。视口
和世界大纲
共同努力,让您能够管理您的级别,前者将向您展示它的外观,而后者将帮助您管理和组织它。与内容浏览器
类似,世界大纲
允许您在目录中组织级别中的对象,不同之处在于内容浏览器
显示项目中的资产,而世界大纲
显示级别中的对象。 -
Details
面板和世界设置
:在屏幕的最右侧,在世界大纲
下方,您将能够看到两个窗口 -Details
面板和世界设置
窗口。Details
窗口允许您编辑您在级别中选择的对象的属性。由于截图中没有选择任何对象,因此它是空的。但是,如果您通过左键单击选择级别中的任何对象,其属性应该会显示在此窗口中,如下面的截图所示:
图 1.3:详细信息选项卡
世界设置
窗口允许您设置级别的整体设置,而不是单个对象的设置。在这里,您可以更改诸如 Kill Z(您希望对象被销毁的高度)和所需的照明设置等内容:
图 1.4:世界设置窗口
工具栏
:在屏幕顶部,您将看到编辑器工具栏
,在那里您将能够保存当前级别、访问项目和编辑器设置,并播放您的级别,等等。
注意
我们将只使用这些工具栏中的一些按钮,即保存当前
、设置
、蓝图
、构建
和播放
按钮。
模式
:在屏幕的最左侧,您将看到模式
窗口。它将允许您将对象拖到您的级别中,例如立方体和球体、光源以及设计用于各种目的的其他类型的对象。
现在我们已经了解了虚幻引擎编辑器的主要窗口,让我们来看看如何管理这些窗口。
编辑器窗口
正如我们所见,虚幻引擎编辑器由许多窗口组成,所有这些窗口都是可调整大小、可移动的,并且都有相应的标签在顶部。您可以点击并按住窗口的标签并拖动它以将其移动到其他位置。您可以通过右键单击它们并选择隐藏
选项来隐藏标签标签:
图 1.5:如何隐藏标签
如果标签标签已被隐藏,您可以通过单击该窗口左上角的黄色三角形使其重新出现,如下图所示:
图 1.6:允许显示窗口标签的黄色三角形
请记住,您可以通过单击编辑器左上角的窗口
按钮来浏览和打开编辑器中的所有可用窗口,包括刚提到的窗口。
您还应该知道的另一件非常重要的事情是如何在编辑器内播放您的关卡(也称为工具栏
,您将看到播放
按钮。如果您点击它,您将开始在编辑器内播放当前打开的关卡。
一旦您点击播放
,您将能够通过使用W、A、S和D键来控制关卡中的玩家角色,使用空格键跳跃,并移动鼠标
来旋转相机:
图 1.7:在编辑器内播放的关卡
然后,您可以按Esc键(Escape)以停止播放关卡。
现在我们已经习惯了一些编辑器的窗口,让我们更深入地了解视口
窗口。
视口导航
我们在前一节中提到,视口
窗口将允许您可视化您的级别,并操纵其中的对象。因为这是您要使用的非常重要的窗口,并且具有许多功能,所以我们将在本节中更多地了解它。
在我们开始学习视口
窗口之前,让我们快速了解一下视口
窗口,它将始终显示当前选定级别的内容,本例中已经创建并与第三人称
模板项目一起生成。在此级别中,您将能够看到四个墙体对象,一个地面对象,一组楼梯和一些其他高架对象,以及由 UE4 模特代表的玩家角色。您可以创建多个级别并通过从内容浏览器
中打开它们来在它们之间切换。
为了操纵和浏览当前选定的级别,您必须使用视口
窗口。如果您在窗口内按住左鼠标按钮,您将能够通过将鼠标左和右移动来水平旋转相机,并通过将鼠标向前和向后移动来前后移动相机。您也可以通过按住右鼠标按钮来实现类似的结果,除了在将鼠标向前和向后移动时相机将垂直旋转,这样您就可以水平和垂直旋转相机。
此外,您还可以通过点击并按住视口
窗口的右鼠标按钮(左鼠标按钮也可以,但由于在旋转相机时没有太多自由度,因此使用它进行移动不太有用)并使用W和S键向前和向后移动,A和D键向侧面移动,E和Q键向上和向下移动。
如果您查看视口
窗口的右上角,您将看到一个带有数字的小摄像机图标,它将允许您更改相机在视口
窗口中移动的速度。
在Viewport
窗口中可以做的另一件事是更改其可视化设置。您可以通过单击当前显示为Lit
的按钮来更改Viewport
窗口中的可视化类型,这将显示所有可用于不同照明和其他类型可视化滤镜的选项。
如果单击Perspective
按钮,您将有选择在透视视图和正交视图之间切换,后者可能会帮助您更快地构建级别。
现在让我们转到操纵对象的主题,也称为 Actor,在您的级别中。
操纵 Actor
在虚幻引擎中,可以放置在级别中的所有对象都称为 Actor。在电影中,演员将是扮演角色的人,但在 UE4 中,您在级别中看到的每个对象,包括墙壁、地板、武器和角色,都是一个 Actor。
每个 Actor 必须有所谓的Transform
属性,这是三个东西的集合:
-
Vector
属性表示该 Actor 在X、Y和Z轴上的位置。矢量只是一个包含三个浮点数的元组,每个轴上的点的位置都有一个。 -
Rotator
属性表示该 Actor 沿X、Y和Z轴的旋转。旋转器也是一个包含三个浮点数的元组,每个轴上的旋转角度都有一个。 -
Vector
属性表示该 Actor 在级别中的比例(大小)在X、Y和Z轴上。这也是三个浮点数的集合,每个轴上都有一个比例值。
Actor 可以在级别中移动、旋转和缩放,这将相应地修改它们的Transform
属性。为了做到这一点,通过左键单击选择级别中的任何对象。您应该看到Move工具出现:
图 1.8:移动工具,允许您在级别中移动 Actor
移动工具是一个三轴标尺,允许您同时在任何轴上移动对象。移动工具的红色箭头(在前面的图像中指向左侧)表示X轴,绿色箭头(在前面的图像中指向右侧)表示Y轴,蓝色箭头(在前面的图像中向上指)表示Z轴。如果您单击并按住这些箭头中的任何一个,然后将它们拖动到级别中,您将在级别中沿该轴移动您的 Actor。如果单击连接两个箭头的手柄,您将同时沿着这两个轴移动 Actor,如果单击所有箭头交汇处的白色球体,您将自由移动 Actor 沿着所有三个轴:
图 1.9:使用移动工具在 Z 轴上移动的 Actor
移动工具将允许您在级别中移动 Actor,但如果您想旋转或缩放 Actor,您需要分别使用旋转和缩放工具。您可以通过按W、E和R键在移动、旋转和缩放工具之间切换。按E以切换到旋转工具:
图 1.10:旋转工具,允许您旋转 Actor
旋转工具将如预期般允许您在级别中旋转 Actor。您可以单击并按住任何弧线以围绕其关联轴旋转 Actor。红色弧线(前图中左上方)将围绕X轴旋转 Actor,绿色弧线(前图中右上方)将围绕Y轴旋转 Actor,蓝色弧线(前图中下方中心)将围绕Z轴旋转 Actor:
图 1.11:在 X 轴周围旋转 30 度之前和之后的立方体
请记住,物体围绕X轴的旋转通常被指定为横滚,它围绕Y轴的旋转通常被指定为俯仰,它围绕Z轴的旋转通常被指定为偏航。
最后,我们有比例工具。按R以切换到它:
图 1.12:比例工具
比例工具将允许您增加和减少角色在X、Y和Z轴上的比例(大小),红色手柄(上图左侧)将在X轴上缩放角色,绿色手柄(上图右侧)将在Y轴上缩放角色,蓝色手柄(上图上方)将在Z轴上缩放角色:
图 1.13:在所有三个轴上缩放前后的角色角色
您还可以通过单击“视口”窗口顶部的以下图标在移动、旋转和缩放工具之间切换:
图 1.14:移动、旋转和缩放工具图标
此外,您可以通过在移动、旋转和缩放工具图标右侧的网格捕捉选项更改移动、旋转和缩放对象的增量。通过按下当前为橙色的按钮,您将能够完全禁用捕捉,通过按下显示当前捕捉增量的按钮,您将能够更改这些增量:
图 1.15:用于移动、旋转和缩放的网格捕捉图标
现在您已经知道如何操作您级别中已经存在的角色,让我们在下一个练习中学习如何向我们的级别添加和删除角色。
练习 1.02:添加和删除角色
在这个练习中,我们将向我们的级别添加和删除角色。
在向您的级别添加角色时,有两种主要方法可以这样做:通过从内容浏览器
拖动资产,或者通过从模式
窗口的放置模式中拖动默认资产。
以下步骤将帮助您完成此练习:
- 如果您进入
ThirdPersonCPP -> Blueprints
目录,您将在内容浏览器
中看到ThirdPersonCharacter
角色。如果您使用左键将该资产拖到您的级别中,您将能够向其中添加该角色的一个实例,并且它将放置在您放开左键的地方:
图 1.16:将 ThirdPersonCharacter 角色的一个实例拖到我们的级别中
- 您也可以从
模式
窗口将一个角色拖到您的级别中:
图 1.17:将圆柱体角色拖到我们的级别中
- 要删除一个角色,您可以简单地选择该角色并按下删除键。您还可以右键单击一个角色,查看有关该角色的许多其他可用选项。
注意
尽管我们不会在本书中涵盖这个主题,但开发人员可以用简单的框和几何图形填充他们的级别,用于原型制作的一种方式是 BSP 刷。这些可以在构建级别时快速塑造成您想要的形状。要了解有关 BSP 刷的更多信息,请访问此页面:docs.unrealengine.com/en-US/Engine/Actors/Brushes
。
通过这样,我们结束了这个练习,并学会了如何向我们的级别添加和删除角色。
现在我们知道如何浏览视口
窗口,让我们了解蓝图角色。
蓝图角色
在 UE4 中,“蓝图”一词可用于指代两种不同的东西:UE4 的可视化脚本语言或特定类型的资产,也称为蓝图类或蓝图资产。
正如我们之前提到的,角色是可以放置在关卡中的对象。这个对象可以是 C++类的实例,也可以是蓝图类的实例,两者都必须从角色类(直接或间接地)继承。那么,C++类和蓝图类之间有什么区别呢?有一些:
-
如果您向 C++类添加编程逻辑,您将可以访问比创建蓝图类时更高级的引擎功能。
-
在蓝图类中,您可以轻松查看和编辑该类的可视组件,例如 3D 网格或触发框碰撞,以及修改在 C++类中定义的属性,这些属性暴露给编辑器,使得管理这些属性更加容易。
-
在蓝图类中,您可以轻松引用项目中的其他资产,而在 C++中,您也可以这样做,但不那么简单,也不那么灵活。
-
在蓝图可视化脚本上运行的编程逻辑在性能方面比 C++类慢。
-
在 C++类中,可以简单地让多个人同时工作而不会在源版本平台上发生冲突,而在蓝图类中,这将导致冲突,因为它被解释为二进制文件而不是文本文件,如果两个不同的人编辑相同的蓝图类,这将导致源版本平台上的冲突。
注意
如果您不知道什么是源版本平台,这是几个开发人员可以在同一项目上工作并且可以更新其他开发人员完成的工作的方式。在这些平台上,通常可以同时编辑同一文件的不同部分,只要它们编辑的是文件的不同部分,并且仍然可以接收其他程序员完成的更新,而不会影响您对同一文件的工作。最流行的源版本平台之一是 GitHub。
请记住,蓝图类可以继承自 C++类或另一个蓝图类。
最后,在我们继续创建我们的第一个蓝图类之前,您应该知道的另一件重要的事情是,您可以在 C++类中编写编程逻辑,然后创建一个从该类继承的蓝图类,但如果您在 C++类中指定了这一点,它也可以访问其属性和方法。您可以让蓝图类编辑在 C++类中定义的属性,以及调用和覆盖函数,使用蓝图脚本语言。我们将在本书中做一些这样的事情。
现在您对蓝图类有了一些了解,让我们在下一个练习中创建自己的蓝图类。
练习 1.03:创建蓝图角色
在这个简短的练习中,我们将学习如何创建一个新的蓝图角色。
以下步骤将帮助您完成此练习:
- 进入
ThirdPersonCPP -> Blueprints
目录,位于“内容浏览器”内,并在其中右键单击。 应该弹出以下窗口:
图 1.18:在内容浏览器内右键单击时出现的选项窗口
此选项菜单包含您可以在 UE4 中创建的资产类型(蓝图只是一种资产类型,以及其他类型的资产,如“关卡”、“材质”和“声音”)。
- 单击“蓝图类”图标以创建一个新的蓝图类。这样做时,您将有选择要继承的 C++或蓝图类的选项:
图 1.19:创建新蓝图类时弹出的选择父类窗口
- 从这个窗口中选择第一个类,
Actor
类。之后,你将自动选择新蓝图类的文本,以便轻松地为它命名。将这个蓝图类命名为TestActor
,然后按Enter
键接受这个名字。
按照这些步骤,你将创建你的蓝图类,完成这个练习。创建完这个资源后,用左键双击它以打开蓝图编辑器。
蓝图编辑器
蓝图编辑器是虚幻引擎编辑器中专门用于蓝图类的子编辑器。在这里,你可以编辑你的蓝图类的属性和逻辑,或者它们的父类,以及它们的视觉外观。
打开一个 Actor Blueprint 类时,你应该会看到蓝图编辑器。这是一个窗口,允许你在 UE4 中编辑蓝图类。让我们了解一下你当前看到的窗口:
图 1.21:事件图窗口,显示三个禁用的事件
你可以通过按住鼠标右键在事件图
中拖动来导航,通过滚动鼠标滚轮来放大和缩小,通过单击鼠标左键或按住并选择节点区域来选择图中的节点。
你也可以在事件图
窗口内右键单击来访问蓝图的操作菜单,该菜单允许你访问在事件图
中可以执行的操作,包括获取和设置变量,调用函数或事件,以及其他许多操作。
蓝图中脚本的工作方式是通过连接节点使用针。有几种类型的节点,如变量、函数和事件。你可以通过针连接这些节点,其中有两种类型的针:
- 执行针: 这些将决定节点执行的顺序。如果你想要执行节点 1 然后执行节点 2,你需要将节点 1 的输出执行针连接到节点 2 的输入执行针,如下面的截图所示:
图 1.22:连接事件 OnReset 节点的输出执行针到 MyVar 的 setter 节点的输入执行针
- 变量针:这些作为参数(也称为输入针),在节点的左侧,并返回值(也称为输出针),在节点的右侧,表示特定类型的值(整数、浮点数、布尔值等):
图 1.23:调用 Get Scalar Parameter Value 函数的节点,它有两个输入变量针和一个输出变量针
让我们通过下一个练习更好地理解这个。
练习 1.04:创建蓝图变量
在这个练习中,我们将看到如何通过创建一个Boolean
类型的新变量来创建蓝图变量。
在蓝图中,变量的工作方式类似于你在 C++中使用的变量。你可以创建它们,获取它们的值,并设置它们。
以下步骤将帮助你完成这个练习:
- 要创建一个新的蓝图变量,前往
我的蓝图
窗口并点击+ 变量
按钮:
图 1.24:在我的蓝图窗口中突出显示的+ 变量按钮,允许你创建一个新的蓝图变量
- 之后,你将自动被允许命名你的新变量。将这个新变量命名为
MyVar
:
图 1.25:命名新变量 MyVar
- 通过点击
工具栏
窗口左侧的编译
按钮来编译你的蓝图。如果你现在查看详细信息
窗口,你应该会看到以下内容:
图 1.26:详细信息窗口中的 MyVar 变量设置
- 在这里,您将能够编辑与此变量相关的所有设置,最重要的设置是
变量名称
,变量类型
和设置末尾的默认值
。布尔变量的值可以通过单击其右侧的灰色框来更改:
图 1.27:从变量类型下拉菜单中可用的变量类型
- 您还可以将变量的 getter 或 setter 拖到
My Blueprint
选项卡中,然后放入事件图
窗口中:
图 1.28:将 MyVar 拖入事件图窗口并选择是否添加 getter 或 setter
Getter 是包含变量当前值的节点,而 setter 是允许您更改变量值的节点。
- 要允许变量在此蓝图类的每个实例中可编辑,您可以单击
My Blueprint
窗口中该变量右侧的眼睛图标:
图 1.29:单击眼睛图标以显示变量并允许其可实例编辑
- 然后,您可以将此类的实例拖到您的级别中,选择该实例,并在编辑器的
详细
窗口中看到更改该变量值的选项:
图 1.30:可以通过该对象的详细面板编辑的 MyVar 变量
有了这个,我们完成了这个练习,现在知道如何创建我们自己的蓝图变量。现在让我们看看如何在下一个练习中创建蓝图函数。
练习 1.05:创建蓝图函数
在这个练习中,我们将创建我们的第一个蓝图函数。在蓝图中,函数和事件是相对类似的,唯一的区别是事件只会有一个输出引脚,通常是因为它是从蓝图类的外部调用的:
图 1.31:事件(左),不需要执行引脚的纯函数调用(中),和正常函数调用(右)
以下步骤将帮助您完成此练习:
- 单击
My Blueprint
窗口内的+函数
按钮:
图 1.32:悬停在+函数按钮上,这将创建一个新函数
-
将新函数命名为
MyFunc
。 -
通过单击
工具栏
窗口中的编译
按钮来编译您的蓝图:
图 1.33:编译按钮
- 如果您现在查看
详细
窗口,您应该会看到以下内容:
图 1.34:选择 MyFunc 函数并添加输入和输出引脚后的详细面板
在这里,您将能够编辑与此函数相关的所有设置,最重要的设置是输入
和输出
在设置末尾。这将允许您指定此函数必须接收和返回的变量。
最后,您可以通过从My Blueprint
窗口单击来编辑此函数的功能。这将在中心窗口中打开一个新选项卡,允许您指定此函数将执行的操作。在这种情况下,此函数每次被调用时将简单地返回false
:
图 1.35:MyFunc 函数的内容,接收一个布尔参数,并返回一个布尔类型
- 要保存对此蓝图类所做的修改,请单击工具栏上
Compile
按钮旁边的Save
按钮。或者,您可以选择使蓝图在成功编译时自动保存。
按照这些步骤,您现在知道如何创建自己的蓝图函数。现在让我们来看一下本章后面将要使用的蓝图节点。
浮点数乘法节点
蓝图包含许多与变量或函数无关的节点。其中一个例子是算术节点(即加法、减法、乘法等)。如果在蓝图操作菜单中搜索float * float
,您将找到浮点数乘法节点。
图 1.36:浮点数乘法节点
此节点允许您输入两个或多个浮点参数(您可以通过单击Add pin
文本右侧的+
图标添加更多参数),并输出所有参数的乘积结果。我们将在本章的后面使用此节点。
BeginPlay 和 Tick
现在让我们来看一下 UE4 中两个最重要的事件:BeginPlay
和Tick
。
如前所述,事件通常会从蓝图类外部调用。在BeginPlay
事件的情况下,当蓝图类的实例被放置在关卡中并且关卡开始播放时,或者在游戏进行中动态生成蓝图类的实例时,将调用此事件。您可以将BeginPlay
事件视为在蓝图类的实例上调用的第一个事件,您可以用它进行初始化。
在 UE4 中了解的另一个重要事件是Tick
事件。如您所知,游戏以一定的帧率运行,最常见的是 30 FPS(每秒帧数)或 60 FPS:这意味着游戏将每秒渲染 30 次或 60 次更新的游戏图像。Tick
事件将在游戏执行此操作时被调用,这意味着如果游戏以 30 FPS 运行,则Tick
事件将每秒被调用 30 次。
转到蓝图类的事件图
窗口,并通过选择它们所有并单击Delete
键来删除三个灰色事件,这将导致事件图
窗口变为空白。之后,在事件图
窗口内部右键单击,输入BeginPlay
,并选择Event BeginPlay
节点,然后单击Enter
键或在蓝图操作菜单中选择该选项。这将导致该事件被添加到事件图
窗口中:
图 1.37:通过蓝图操作菜单将 BeginPlay 事件添加到事件图窗口中
右键单击事件图窗口内部,输入Tick
,并选择Event Tick
节点。这将导致该事件被添加到事件图窗口中:
图 1.38:Tick 事件
与BeginPlay
事件不同,Tick
事件将带有一个参数DeltaTime
。此参数是一个浮点数,表示自上一帧渲染以来经过的时间。如果您的游戏以 30 FPS 运行,则每个帧之间的间隔(增量时间)平均为 1/30 秒,约为 0.033 秒(33.33 毫秒)。如果渲染帧 1,然后 0.2 秒后渲染帧 2,则帧 2 的增量时间将为 0.2 秒。如果帧 3 在帧 2 之后 0.1 秒渲染,则帧 3 的增量时间将为 0.1 秒,依此类推。
但是为什么DeltaTime
参数如此重要?让我们看看以下情景:您有一个蓝图类,它使用Tick
事件在每次渲染帧时在 Z 轴上增加 1 个单位的位置。然而,您面临一个问题:玩家可能以不同的帧率运行游戏,比如 30 FPS 和 60 FPS。以 60 FPS 运行游戏的玩家将导致Tick
事件被调用的次数是以 30 FPS 运行游戏的玩家的两倍,并且蓝图类将因此移动速度加快两倍。这就是增量时间的作用所在:因为以 60 FPS 运行游戏的Tick
事件被调用的增量时间值较低(渲染帧之间的间隔更小),您可以使用该值来改变 Z 轴上的位置。尽管以 60 FPS 运行游戏的Tick
事件被调用的次数是 30 FPS 运行游戏的两倍,但其增量时间是一半,因此一切都平衡了。这将导致以不同帧率玩游戏的两个玩家获得相同的结果。
注意
如果您希望一个使用增量时间移动的蓝图移动得更快或更慢,可以将增量时间乘以您希望它每秒移动的单位数(例如,如果您希望一个蓝图在 Z 轴上每秒移动 3 个单位,您可以告诉它每帧移动3 * DeltaTime
个单位)。
现在让我们尝试另一个练习,这将涉及使用蓝图节点和引脚。
练习 1.06:在 Z 轴上偏移 TestActor 类
在这个练习中,您将使用BeginPlay
事件在游戏开始播放时偏移(移动)TestActor
在 Z 轴上的位置。
以下步骤将帮助您完成此练习:
-
打开
TestActor
蓝图类。 -
使用“蓝图操作”菜单,将“事件 BeginPlay”节点添加到图表中,如果尚未添加。
-
添加
AddActorWorldOffset
函数,并将BeginPlay
事件的输出执行引脚连接到此函数的输入执行引脚。此函数负责在预期轴(X、Y和Z)上移动 Actor,并接收以下参数:
-
Target
:应调用此函数的 Actor,这将是调用此函数的 Actor。默认行为是在调用此函数的 Actor 上调用此函数,这正是我们想要的,并且使用self
属性显示。 -
DeltaLocation
:我们希望在三个轴上偏移此 Actor 的量:X、Y 和 Z。 -
我们不会涉及另外两个参数
Sweep
和Teleport
,所以您可以将它们保持不变。它们都是布尔类型,应该保持为false
:
图 1.39:BeginPlay 事件调用 AddActorWorldOffset 函数
- 拆分
Delta Location
输入引脚,这将导致将此Vector
属性拆分为三个浮点属性。您可以通过右键单击它们并选择“拆分结构引脚”来对由一个或多个子类型组成的任何变量类型执行此操作(您无法对浮点类型执行此操作,因为它不包含任何变量子类型):
图 1.40:将 Delta 位置参数从矢量拆分为三个浮点数
-
通过单击鼠标左键,输入该数字,然后按Enter键,将
Delta Location
的Z
属性设置为 100 个单位。这将导致我们的TestActor
在游戏开始时在 Z 轴上向上移动 100 个单位。 -
使用“组件”窗口向您的
TestActor
添加一个立方体形状,以便我们可以看到我们的角色。您可以通过单击“+添加组件”按钮,输入Cube
,然后选择“基本形状”部分下的第一个选项来执行此操作:
图 1.41:添加一个立方体形状
-
通过单击“编译”按钮来编译和保存您的蓝图类。
-
回到级别的“视口”窗口,并在级别中放置一个您的
TestActor
蓝图类的实例,如果您还没有这样做的话:
图 1.42:将 TestActor 的实例添加到级别
- 当您播放级别时,您应该注意到我们添加到级别中的
TestActor
处于更高的位置:
图 1.43:游戏开始时 TestActor 在 Z 轴上增加其位置
- 在进行这些修改后,通过按下Ctrl + S或单击编辑器“工具栏”上的“保存当前”按钮来保存我们对级别所做的更改。
在这个练习中,您已经学会了如何创建您自己的蓝图脚本逻辑的第一个角色蓝图类。
注意
TestActor
蓝图资产和此练习的最终结果的“地图”资产都可以在这里找到:packt.live/3lfYOa9
。
现在我们已经做到了这一点,让我们更多地了解ThirdPersonCharacter
蓝图类。
第三人称角色蓝图类
让我们来看看ThirdPersonCharacter
蓝图类,这是代表玩家控制的角色的蓝图,并看看它包含的角色组件。
转到“内容浏览器”中的“ThirdPersonCPP->蓝图”目录,并打开ThirdPersonCharacter
资产:
图 1.44:ThirdPersonCharacter 蓝图类
在之前的部分中,我们介绍了蓝图编辑器中的“组件”窗口,我们提到了角色组件。
角色组件是必须存在于角色内部的实体,并允许您将角色的逻辑分散到几个不同的角色组件中。在这个蓝图中,我们可以看到有四个可视表示的角色组件:
-
显示 UE4 模特的骨骼网格组件
-
一个摄像头组件,显示玩家将能够从哪里看到游戏
-
一个箭头组件,允许我们看到角色面对的方向(这主要用于开发目的,而不是在游戏进行时)
-
指定此角色的碰撞范围的胶囊组件
如果您查看“组件”窗口,您会看到一些比我们在“视口”窗口中看到的更多的角色组件。这是因为一些角色组件没有视觉表示,纯粹由 C++或蓝图代码组成。我们将在下一章和第九章“音频-视觉元素”中更深入地了解角色组件。
如果你看一下这个蓝图类的“事件图”窗口,你会发现它基本上是空的,就像我们在TestActor
蓝图类中看到的那样,尽管它有一些与之相关的逻辑。这是因为该逻辑是在 C++类中定义的,而不是在这个蓝图类中。我们将在下一章中看看如何做到这一点。
为了解释这个蓝图类的骨骼网格组件,我们应该先讨论网格和材料。
网格和材料
要使计算机可视化表示 3D 对象,需要两样东西:3D 网格和材料。
网格
3D 网格允许您指定对象的大小和形状,就像这个代表猴子头部的网格:
图 1.45:猴子头部的 3D 网格
网格由多个顶点、边和面组成。顶点只是具有X、Y和Z位置的 3D 坐标;边是两个顶点之间的连接(即一条线);面是三个或更多边的连接。您可以在前面的图中看到网格的各个顶点、边和面,其中每个面的颜色在白色和黑色之间变化,取决于面上反射的光线量。如今,视频游戏可以以这样的方式渲染网格,其中有成千上万的顶点,以至于您无法分辨出单个顶点,因为它们太靠在一起了。
材质
另一方面,材质允许您指定网格的表示方式。它们允许您指定网格的颜色,在其表面绘制纹理,甚至操纵其各个顶点。
创建网格是一件事,在撰写本书时,UE4 尚未得到适当支持,应在另一款软件(例如 Blender 或 Autodesk Maya)中完成,因此我们不会在这里详细介绍这一点。但是,我们将学习如何为现有网格创建材质。
在 UE4 中,您可以通过网格组件添加网格,这些网格继承自 Actor 组件类。有几种类型的网格组件,但最重要的两种是静态网格组件,用于没有动画的网格(例如,立方体,静态级别几何体),以及骨骼网格组件,用于具有动画的网格(例如,播放移动动画的角色网格)。正如我们之前所看到的,ThirdPersonCharacter
蓝图类包含骨骼网格组件,因为它用于表示播放移动动画的角色网格。在下一章中,我们将学习如何将资产(例如网格)导入到我们的 UE4 项目中。
现在让我们在下一个练习中看一下 UE4 中的材质。
在 UE4 中操作材质
在本节中,我们将看一看材质在 UE4 中的工作原理。
返回到您的“级别视口”窗口,并选择此“立方体”对象:
图 1.46:立方体对象,旁边的文字写着地板上的第三人称
查看“详细信息”窗口,您将能够看到与此对象的“静态网格”组件关联的网格和材质:
图 1.47:立方体对象的静态网格组件的材质(元素 0)属性
注意
请记住,网格可以有多个材质,但必须至少有一个。
单击“材质”属性旁边的放大镜图标,以转到“内容浏览器”中该材质的位置。该图标适用于编辑器中对任何资产的任何引用,因此您也可以对立方体对象的“静态网格”引用执行相同操作:
图 1.48:放大镜图标(左),可带您到该资产在内容浏览器中的位置(右)
双击使用鼠标左键打开“材质”编辑器中的资产。让我们来分解“材质编辑器”中的窗口:
图 1.49:将材质编辑器窗口分解为五个部分
-
图表
:在编辑器的正中央,您将看到图表
窗口。类似于蓝图编辑器的事件图表
窗口,材质编辑器的图表也是基于节点的,您将在此找到通过引脚连接的节点,尽管这里不会找到执行引脚,只有输入和输出引脚。 -
Palette
:在屏幕的右边缘,你会看到Palette
窗口,你可以在这里搜索所有可以添加到Graph
窗口的节点。你也可以像在蓝图编辑器的事件图
窗口中一样,通过在Graph
窗口内右键单击并输入你想要添加的节点来实现。 -
Viewport
:在屏幕的左上角,你会看到Viewport
窗口。在这里,你可以预览你的材质的结果,以及它在一些基本形状上的外观,比如球体、立方体和平面。 -
Details
:在屏幕的左下角,你会看到Details
窗口,类似于蓝图编辑器,你可以查看材质
资产的细节,或者查看Graph
窗口中当前选定节点的细节。 -
Toolbar
:在屏幕的顶部边缘,你会看到Toolbar
窗口,你可以在这里应用和保存对材质的更改,以及执行与Graph
窗口相关的几个操作。
在 UE4 的每个材质编辑器中,你都会找到一个名为Material
的节点,通过将该节点的引脚连接到其他节点,你可以指定与之相关的几个参数。
在这种情况下,你可以看到有一个名为0.7
的节点被插入到Roughness
引脚中。这个节点是一个Constant
节点,允许你指定与之关联的数字 - 在这种情况下是0.7
。你可以创建单个数字、2 个向量(例如,(1, 0.5)
)、3 个向量(例如,(1, 0.5, 4)
)和 4 个向量(例如,(1,0.5, 4, 0)
)的常数节点。要创建这些节点,你可以按住1
、2
、3
或4
数字键,同时在Graph
窗口上按下鼠标左键。
材质有几个输入参数,让我们来看一些最重要的参数:
-
BaseColor
:这个参数就是材质的颜色。通常,常数或纹理样本被用来连接到这个引脚,要么让一个物体成为特定颜色,要么映射到特定纹理。 -
Metallic
:这个参数将决定你的物体看起来有多像金属表面。你可以通过连接一个范围从 0(非金属)到 1(非常金属)的常数单个数字节点来实现这一点。 -
Specular
:这个参数将决定你的物体将反射多少光。你可以通过连接一个范围从 0(不反射任何光)到 1(反射所有光)的常数单个数字节点来实现这一点。如果你的物体已经非常金属,你将看不到任何或很少的差异。 -
Roughness
:这个参数将决定你的物体反射的光有多少会被散射(光散射得越多,这个物体反射周围的东西就越不清晰)。你可以通过连接一个范围从 0(物体基本上变成镜子)到 1(这个物体上的反射是模糊不清)的常数单个数字节点来实现这一点。
注意
要了解更多关于上述材质
输入的信息,请访问docs.unrealengine.com/en-US/Engine/Rendering/Materials/MaterialInputs
。
UE4 还允许你导入图像(.jpeg
、.png
)作为纹理
资产,然后可以在材质中使用纹理样本
节点引用:
图 1.50:纹理样本节点,允许你指定一个纹理并将其用作引脚的颜色通道
注意
我们将在下一章中看一下如何将文件导入到 UE4 中。
要创建一个新的材质
资产,你可以在Content Browser
内右键单击要创建新资产的目录,这将允许你选择要创建的资产,然后选择Material
。
现在您知道如何在 UE4 中创建和操作材质了。
现在让我们开始本章的活动,这将是本书的第一个活动。
活动 1.01:在 Z 轴上无限推进 TestActor
在这个活动中,您将使用TestActor
的Tick
事件来使其在Z轴上无限移动,而不仅仅在游戏开始时执行一次。
以下步骤将帮助您完成此活动:
-
打开
TestActor
蓝图类。 -
将
事件 Tick
节点添加到蓝图的事件图
窗口中。 -
添加
AddActorWorldOffset
函数,拆分其DeltaLocation
引脚,并将Tick
事件的输出执行引脚连接到此函数的输入执行引脚,类似于我们在练习 1.01,创建虚幻引擎 4 项目中所做的。 -
在
事件图
窗口中添加一个Float Multiplication节点。 -
将
Tick
事件的Delta Seconds
输出引脚连接到Float Multiplication节点的第一个输入引脚。 -
创建一个
float
类型的新变量,称为VerticalSpeed
,并将其默认值设置为25
。 -
在
事件图
窗口中为VerticalSpeed
变量添加一个 getter,并将其引脚连接到Float Multiplication节点的第二个输入引脚。之后,将Float Multiplication节点的输出引脚连接到AddActorWorldOffset
函数的Delta Location Z
引脚。 -
删除我们在练习 1.01,创建虚幻引擎 4 项目中创建的
BeginPlay
事件和连接到它的AddActorWorldOffset
函数。 -
播放关卡,注意我们的
TestActor
随着时间从地面上升到空中:
图 1.51:TestActor 在垂直方向上推进
完成这些步骤后,我们结束了这个活动——本书中的第一个活动。我们现在已经巩固了向蓝图编辑器的事件图
窗口添加和删除节点,以及使用Tick
事件及其DeltaSeconds
属性来创建跨不同帧率保持一致性的游戏逻辑。
注意
此活动的解决方案可以在此处找到:packt.live/338jEBx
。
TestActor
蓝图资产可以在这里找到:packt.live/2U8pAVZ
。
总结
通过完成本章,您已经迈出了游戏开发之旅的第一步,了解了虚幻引擎 4。您现在知道如何浏览虚幻引擎编辑器,操作关卡内的角色,创建自己的角色,使用蓝图脚本语言,以及在虚幻引擎 4 中如何表示 3D 对象。
希望您意识到在您面前有一个充满可能性的世界,并且在使用这个游戏开发工具创建各种东西方面,天空是极限。
在下一章中,您将从头开始重新创建本章自动生成的项目模板。您将学习如何创建自己的 C++类,然后创建可以操作其父类声明的属性的蓝图类,以及如何将角色网格和动画导入到虚幻引擎 4 中,以及熟悉其他与动画相关的资产,如动画蓝图。
第二章:使用虚幻引擎
概述
本章将重点介绍虚幻引擎中许多基本概念和特性。您将学习如何创建 C++项目,如何进行一些基本调试,以及如何处理特定角色的动画。
通过本章结束时,您将能够创建 C++模板项目,能够在 Visual Studio 中调试代码,了解文件夹结构和相关的最佳实践,并最终能够根据状态设置角色动画。
介绍
在上一章中,我们介绍了 Epic Games Launcher 的基础知识,以及虚幻编辑器的基本原理。我们了解了如何处理对象以及基本级别上的蓝图,还探索了第一人称模板。在本章中,我们将通过探索第三人称模板和处理输入和动画来进一步建立这些基础知识。
游戏开发可以使用多种语言,如 C、C++、Java、C#,甚至 Python。虽然每种语言都有优缺点,但在本书中我们将使用 C++,因为它是虚幻引擎中主要使用的编程语言。
在本章中,我们将带您快速了解如何在 UE4 中创建 C++项目和基本级别的调试。调试代码非常重要,因为它有助于开发人员处理错误。提供的工具非常方便,对于任何虚幻引擎开发人员都是必不可少的。
接下来,我们将深入了解在虚幻引擎中创建游戏和体验所涉及的核心类。您将探索游戏模式和相关的类概念,然后进行一项练习,以获得对此的实际理解。
本章的最后一部分是关于动画的。几乎每个游戏都包含动画,有些只是非常基本的,但有些则达到了非常高的水平,包括引人入胜的细节,这些细节对游戏体验至关重要。虚幻引擎提供了几种工具,您可以使用这些工具来创建和处理动画,包括具有复杂图表和状态机的动画蓝图。
创建和设置空白 C++项目
在每个项目开始时,您可能希望从 Epic 提供的模板中选择任何一个(其中包含准备执行的基本代码)并在此基础上进行开发。大部分/有时候,您可能需要设置一个空白项目,以便根据自己的需求进行开发。我们将在接下来的练习中学习如何做到这一点。
练习 2.01:创建一个空白的 C++项目
在这个练习中,您将学习如何从 Epic 提供的模板中创建一个空白的 C++项目。这将成为您未来许多 C++项目的基础。
以下步骤将帮助您完成这个练习:
-
从 Epic Games Launcher 启动虚幻引擎 4.24。
-
点击“游戏”部分,然后点击“下一步”。
-
确保选择“空白”项目模板,然后点击“下一步”。
-
点击“蓝图”部分下拉菜单,选择
C++
。
注意
确保项目文件夹和项目名称分别指定了适当的目录和名称。
设置好一切后,点击“创建项目”按钮。在本例中,我们的项目目录位于一个名为UnrealProjects
的文件夹中,该文件夹位于 E 驱动器内。项目名称设置为MyBlankProj
(建议您遵循这些名称和项目目录,但如果您愿意,也可以使用自己的名称)。
注意
项目名称不能包含任何空格。最好将虚幻目录放在驱动器的根目录附近(以避免在创建或导入资产到项目工作目录时遇到 256 字符路径限制等问题;对于小型项目,可能没问题,但对于更大规模的项目,文件夹层次可能会变得过于复杂,这一步很重要)。
您会注意到,在生成代码并创建项目文件后,项目将被打开,并附带其 Visual Studio 解决方案(.sln)文件。
注意
确保 Visual Studio 解决方案配置设置为 Development Editor,并且解决方案平台设置为 Win64 以进行桌面开发:
图 2.1:Visual Studio 部署设置
通过完成这个练习,我们现在知道如何在 UE4 上创建一个空的 C++项目,以及其中的注意事项。
在下一节中,我们将简要讨论文件夹结构,以及虚幻开发人员使用的最基本和最常用的文件夹结构格式。
虚幻引擎中的内容文件夹结构
在您的项目目录(E:/UnrealProjects/MyBlankProj
在我们的案例中)中,您会看到一个Content
文件夹。这是您的项目用于不同类型资产和项目相关数据(包括蓝图)的主要文件夹。C++代码放入项目的Source
文件夹中。请注意,最佳做法是通过虚幻编辑器直接创建新的 C++代码文件,因为这简化了流程并减少了错误。
您可以使用许多不同的策略来组织Content
文件夹中的数据。最基本和易于理解的是使用文件夹名称来表示其中的内容类型。因此,Content
文件夹目录结构可能类似于packt.live/3lCVFkR
中的示例。在这个示例中,您可以看到每个文件都被分类地放在表示其类型的文件夹名称下的第一级,随后的级别进一步将其分组到有意义的文件夹中。
注意
所有蓝图的名称应以BP
为前缀(以区分它们与虚幻引擎使用的默认蓝图)。其余前缀是可选的(但最好的做法是使用前面显示的前缀格式)。
在下一节中,我们将看一下 Visual Studio 解决方案。
使用 Visual Studio 解决方案
虚幻引擎中的每个 C++项目都有一个 Visual Studio 解决方案。这反过来驱动了所有的代码,并为开发人员提供了在运行状态下设置执行逻辑和调试代码的能力。
解决方案分析
项目目录中生成的 Visual Studio 解决方案(.sln)文件包含了整个项目和任何添加到其中的相关代码。
让我们来看看 Visual Studio 中存在的文件。双击 .sln 文件在 Visual Studio 中打开它。
在Solution Explorer
中,您将看到两个名为Engine
和Games
的项目。
引擎项目
在基本层面上,虚幻引擎本身就是一个 Visual Studio 项目,并有自己的解决方案文件。这包含了在虚幻引擎中共同工作的所有代码和第三方集成。该项目中的所有代码称为“源”代码。
引擎项目由当前用于该项目的虚幻引擎的外部依赖项、配置、插件、着色器和源代码组成。您可以随时浏览UE4 -> Source
文件夹,查看任何引擎代码。
注意
由于虚幻引擎是开源的,Epic 允许开发人员查看和编辑源代码以满足其需求和要求。但是,您不能编辑通过 Epic Games Launcher 安装的虚幻引擎版本的源代码。要能够对源代码进行更改和构建,您需要下载虚幻引擎的源代码版本,可以在 GitHub 上找到。您可以使用以下指南下载虚幻引擎的源代码版本:docs.unrealengine.com/en-US/GettingStarted/DownloadingUnrealEngine/index.html
下载后,您还可以参考以下指南来编译/构建新下载的引擎:docs.unrealengine.com/en-US/Programming/Development/BuildingUnrealEngine/index.html
游戏项目
在Games
目录下是解决方案文件夹,名称为您的项目。展开后,您会找到一组文件夹。您将关注以下内容:
-
配置文件夹:包含为项目和构建设置的所有配置(这些可以选择性地具有特定平台(如 Windows、Android、iOS、Xbox 或 PS)的设置)。
-
插件文件夹:这是一个可选文件夹,当您添加任何第三方插件(从 Epic Marketplace 下载或通过互联网获取)时会创建。该文件夹将包含与该项目相关的所有插件的源代码。
-
源文件夹:这是我们将要使用的主要文件夹。它将包含构建目标文件,以及项目的所有源代码。以下是源文件夹中默认文件的描述:
-
.Target.cs
扩展名,以及以Build.cs
结尾的一个构建文件。 -
ProjectName 代码文件(.cpp 和.h):默认情况下,为每个项目创建这些文件,并包含用于运行默认游戏模块代码的代码。
-
ProjectNameGameModeBase 代码文件(.cpp 和.h):默认情况下,会创建一个空的项目游戏模式基类。在大多数情况下通常不会使用。
-
ProjectName.uproject 文件:包含用于提供有关项目的基本信息以及与之关联的插件列表的描述符。
在 Visual Studio 中调试代码
Visual Studio 提供了强大的调试功能,通过在代码中设置断点。它使用户能够在特定代码行暂停游戏,以便开发人员可以查看变量的当前值,并以受控的方式逐步执行代码和游戏(可以逐行进行,逐个函数进行等)。
当您的游戏项目中有大量变量和代码文件,并且希望以逐步方式查看变量的值被更新和使用以调试代码、找出问题并解决问题时,这将非常有用。调试是任何开发人员工作的基本过程,只有经过许多连续的调试、分析和优化周期,项目才能足够完善以进行部署。
现在您已经对 Visual Studio 解决方案有了基本的了解,我们将继续并进行一个实际的练习。
练习 2.02:调试第三人称模板代码
在这个练习中,您将使用虚幻引擎的第三人称模板创建一个项目,并将在 Visual Studio 中调试代码。我们将调查模板项目的Character
类中名为BaseTurnRate
的变量的值。我们将看到随着我们逐行移动代码,该值如何更新。
以下步骤将帮助您完成此练习:
-
从 Epic Games Launcher 启动虚幻引擎。
-
点击
Games
部分,然后点击下一步
。 -
选择
Third Person
,然后点击下一步
。 -
选择 C++,将项目名称设置为
ThirdPersonDebug
,然后点击创建项目
按钮。 -
现在,关闭虚幻编辑器,转到 Visual Studio 解决方案,并打开
ThirdPersonDebugCharacter.cpp
文件:
图 2.2:ThirdPersonDebugCharacter.cpp 文件位置
- 左键单击在第
18
行左侧的栏上。应该会出现一个红色的圆点图标(您可以再次单击它将其关闭):
图 2.3:碰撞胶囊初始化代码
在这里,我们正在获取角色的capsule
组件(在第三章,角色类组件和蓝图设置中进一步解释),默认情况下是根组件。然后,我们调用它的InitCapsuleSize
方法,该方法接受两个参数:InRadius
浮点数和InHalfHeight
浮点数。
- 确保 VS 中的解决方案配置设置为
开发编辑器
,然后点击本地 Windows 调试器
按钮:
图 2.4:Visual Studio 构建设置
- 等到您能在左下角看到以下窗口为止:
注意
如果窗口没有弹出,您可以通过在调试
> 窗口
> 自动
下手动打开窗口。此外,您也可以使用本地
。
图 2.5:Visual Studio 变量监视窗口
this
显示了对象本身。对象包含它存储的变量和方法,通过展开它,我们能够看到整个对象及其变量在当前代码执行行的状态。
-
展开
this
,然后展开ACharacter
,然后展开CapsuleComponent
。在这里,您可以看到CapsuleHalfHeight = 88.0
和CapsuleRadius = 34.0
变量的值。在初始的红点所在的第18
行旁边,您会看到一个箭头。这意味着代码已经到达第17
行的末尾,尚未执行第18
行。 -
点击
步进
按钮进入下一行代码(快捷键:F11)。步进
将进入到该行内部的代码(如果存在)。另一方面,步过
将只执行当前代码并移动到下一行。由于当前行上没有函数,步进
将模仿步过
功能。
图 2.6:调试步进
- 请注意,箭头已移动到第
21
行,并且变量已经更新。CapsuleHalfHeight = 96.0
和CapsuleRadius = 42.0
以红色突出显示。还要注意,BaseTurnRate
变量初始化为0.0
:
图 2.7:BaseTurnRate 初始值
- 再次按下(F11)进入到第
22
行。现在,BaseTurnRate
变量的值为45.0
,BaseLookUpRate
初始化为0.0
,如下截图所示:
图 2.8:BaseTurnRate 更新的值
- 再次按下(F11)进入到第
27
行。现在,BaseLookUpRate
变量的值为45.0
。
同样,您被鼓励进入并调试代码的其他部分,不仅要熟悉调试器,还要了解代码在幕后是如何工作的。
通过完成这个练习,您已经学会了如何在 Visual Studio 中设置调试点,以及在某一点停止调试,然后逐行继续观察对象及其变量的值。这对于任何开发人员来说都是一个重要的方面,许多人经常使用这个工具来消除代码中的烦人错误,特别是当代码流量很大,变量的数量相当多时。
注意
在任何时候,您都可以通过顶部菜单栏上的以下按钮停止调试、重新开始调试或继续执行其余代码:
图 2.9:Visual Studio 中的调试工具
现在,我们将看一下如何将资产导入到虚幻项目中。
导入所需资产
虚幻引擎为用户提供了导入各种文件类型的能力,以便用户自定义其项目。开发人员可以调整和玩弄几种导入选项,以匹配其所需的设置。
游戏开发者经常导入的一些常见文件类型包括场景、网格、动画(从 Maya 和其他类似软件导出)、电影文件、图像(主要用于用户界面)、纹理、声音、CSV 文件中的数据和字体。这些文件可以从 Epic Marketplace 或其他途径(如互联网)获得,并在项目中使用。
资产可以通过将它们拖放到内容
文件夹中来导入,也可以通过在内容浏览器
中点击导入
按钮来导入。
现在让我们来进行一个练习,学习如何导入 FBX 文件以及如何完成这个操作。
练习 2.03:导入角色 FBX 文件
这个练习将专注于从 FBX 文件中导入 3D 模型。FBX 文件被广泛用于导出和导入 3D 模型,以及它们的材质、动画和纹理。
以下步骤将帮助您完成这个练习:
- 从 GitHub 的
Chapter02
->Exercise2.03
->ExerciseFiles
目录中下载SK_Mannequin.FBX
,ThirdPersonIdle.FBX
,ThirdPersonRun.FBX
和ThirdPersonWalk.FBX
文件。
注意
ExerciseFiles
目录可以在 GitHub 的以下链接找到:packt.live/2IiqTzq
。
-
打开我们在练习 2.01中创建的空白项目,创建一个空的 C++项目。
-
在项目的
内容浏览器
界面中,点击导入
:
图 2.10:内容浏览器导入按钮
-
浏览到我们在步骤 1中下载的文件目录,选择
SK_Mannequin.FBX
,然后点击打开
按钮。 -
确保
导入动画
按钮是全部导入
按钮。您可能会收到一个警告,指出没有平滑组
。您现在可以忽略这个警告。这样,您就成功地从 FBX 文件中导入了一个骨骼网格。现在,我们需要导入它的动画。 -
再次点击
导入
按钮,浏览到我们在步骤 1中创建的文件夹,并选择ThirdPersonIdle.fbx
,ThirdPersonRun.fbx
和ThirdPersonWalk.fbx
。然后点击打开
按钮。 -
确保骨架设置为您在步骤 5中导入的骨架,然后点击
全部导入
:
图 2.11:动画 FBX 导入选项
-
现在,您可以在
内容浏览器
中看到三个动画(ThirdPersonIdle
,ThirdPersonRun
和ThirdPersonWalk
)。 -
如果您双击
ThirdPersonIdle
,您会注意到左臂下垂。这意味着存在重定向问题。当动画与骨架分开导入时,虚幻引擎会将所有骨骼从动画映射到骨架,但有时会导致故障。我们现在要解决这个故障。
图 2.12:ThirdPersonIdle UE4 人体模型动画故障
- 打开
SK_Mannequin
骨骼网格,并打开骨架树
选项卡(如果之前没有打开)。
图 2.13:SK_Mannequin 骨架树选项卡选择
- 在
选项
下启用显示重定向选项
复选框。
图 2.14:启用重定向选项
-
现在在骨架树中,减少
spine_01
,thigh_l
和thigh_r
骨骼,以便更好地可见。 -
现在选择
spine_01
,thigh_l
和thigh_r
骨骼。在它们上面右键单击,然后在菜单中点击递归设置平移重定向骨架
按钮。这将修复我们之前遇到的骨骼平移问题。 -
重新打开
ThirdPersonIdle
动画
,以验证悬臂是否已经修复。
图 2.15:修复的 ThirdPersonIdle 动画
注意
您可以在 GitHub 的Chapter02
-> Exercise2.03
-> Ex2.03-Completed.rar
目录中找到完整的练习代码文件,链接如下:packt.live/2U8AScR
解压.rar
文件后,双击.uproject
文件。您会看到一个提示,询问是否要立即重建?
。点击该提示上的是
,这样它就可以构建必要的中间文件,然后应该自动在虚幻编辑器中打开项目。
通过完成这个练习,您已经了解了如何导入资产,更具体地说,导入了一个 FBX 骨骼网格和动画数据到您的项目中。对于许多游戏开发者的工作流程来说,这是至关重要的,因为资产是整个游戏的构建模块。
在下一节中,我们将看一下用于创建游戏的虚幻核心类,它们对于创建游戏或体验有多重要,以及如何在项目中使用它们。
虚幻游戏模式类
考虑这样一种情况,您希望能够暂停游戏。所有必要的逻辑和实现,以便能够暂停游戏的类将被放置在一个单独的类中。这个类将负责处理玩家进入游戏时的游戏流程。游戏流程可以是游戏中发生的任何动作或一系列动作。例如,游戏暂停、播放和重新开始被认为是简单的游戏流程动作。同样,在多人游戏的情况下,我们需要将所有与网络相关的游戏逻辑放在一起。这正是游戏模式类的作用。
游戏模式是一个驱动游戏逻辑并对玩家施加游戏相关规则的类。它基本上包含有关当前正在进行的游戏的信息,包括游戏变量和事件,这些将在本章后面提到。游戏模式可以容纳所有游戏对象的管理器,它是一个单例类,并且可以被游戏中的任何对象或抽象类直接访问。
与所有其他类一样,游戏模式类可以在蓝图或 C++中进行扩展。这可以用来包括可能需要的额外功能和逻辑,以便让玩家了解游戏内发生的情况。
让我们来看一些放在游戏模式类中的示例游戏逻辑:
-
限制允许进入游戏的玩家数量
-
控制新连接玩家的生成位置和玩家控制器逻辑
-
跟踪游戏得分
-
跟踪游戏胜利/失败条件。
-
实现游戏结束/重新开始游戏场景
在下一节中,我们将查看游戏模式提供的默认类。
游戏模式默认类
除了自身之外,游戏模式使用了几个类来实现游戏逻辑。它允许您为其以下默认值指定类:
-
游戏会话类:处理管理员级别的游戏流程,如登录批准。
-
游戏状态类:处理游戏状态,以便客户端可以看到游戏内发生的情况。
-
玩家控制器类:用于控制和操纵角色的主要类。可以被视为决定要做什么的大脑。
-
玩家状态类:保存玩家在游戏中的当前状态。
-
HUD 类:处理显示给玩家的用户界面。
-
默认 Pawn 类:玩家控制的主要角色。这本质上是玩家角色。
-
DefaultPawn
类,旁观者 Pawn 类指定了负责旁观游戏的 Pawn。 -
重播旁观玩家控制器:负责在游戏内回放期间操纵回放的玩家控制器。
-
服务器状态复制器类:负责复制服务器状态网络数据。
您可以使用默认类,也可以为自定义实现和行为指定自己的类。这些类将与游戏模式一起工作,并且将自动运行,而无需放置在世界中。
游戏事件
在多人游戏方面,当许多玩家进入游戏时,处理逻辑以允许他们进入游戏,维护其状态,并允许他们查看其他玩家的状态并处理其交互变得至关重要。
游戏模式为您提供了几个可以重写以处理多人游戏逻辑的事件。以下事件对于网络功能和能力(它们主要用于此目的)特别有用:
-
“在登录后”:此事件在玩家成功登录游戏后调用。从这一点开始,可以在玩家控制器类上调用复制逻辑(用于多人游戏中的网络)。
-
“处理新玩家的开始”:此事件在“在登录后”事件之后调用,可用于定义新进入玩家的情况。默认情况下,它为新连接的玩家创建一个角色。
-
“在指定位置生成默认角色”:此事件触发游戏中实际的角色生成。新连接的玩家可以在特定的变换位置或放置在关卡中的预设玩家起始位置生成(可以通过将玩家起始位置从模型窗口拖放到世界中来添加)。
-
“在注销时”:当玩家离开游戏或被销毁时调用此事件。
-
在重新开始玩家时:调用此事件以重新生成玩家。与“在指定位置生成默认角色”类似,玩家可以在特定的变换位置或预先指定的位置(使用玩家起始位置)重新生成。
网络
游戏模式类不会被复制到任何客户端或加入的玩家。它的范围仅限于生成它的服务器。本质上,客户端-服务器模型规定客户端只能作为服务器上进行游戏的输入。因此,游戏逻辑不应存在于客户端,而应仅存在于服务器。
GameModeBase 与 GameMode
从 4.14 版本开始,Epic 引入了AGameModeBase
类,它充当所有游戏模式类的父类。它本质上是AGameMode
类的简化版本。
然而,游戏模式类包含一些更适合多人射击类型游戏的附加功能,因为它实现了比赛状态的概念。默认情况下,“游戏模式基类”包含在基于模板的新项目中。
游戏模式还包含一个状态机,用于处理并跟踪玩家的状态。
关卡
在游戏中,关卡是游戏的一个部分或部分。由于许多游戏非常庞大,它们被分解为不同的关卡。加载感兴趣的关卡供玩家玩耍,然后当他们完成后,可能会加载另一个关卡(同时当前的关卡将被加载出)以便玩家可以继续。要完成游戏,玩家通常需要完成一组特定任务以进入下一关,最终完成游戏。
游戏模式可以直接应用于关卡。加载关卡时,将使用分配的游戏模式类来处理该特定关卡的所有逻辑和游戏玩法,并覆盖项目的游戏模式。可以在打开关卡后使用“世界设置”选项卡进行应用。
关卡蓝图是一个与关卡一起运行的蓝图,但不能在关卡范围之外访问。游戏模式可以在任何蓝图(包括关卡蓝图)中通过“获取游戏模式”节点访问。稍后可以将其转换为您的游戏模式类,以获取对其的引用。
注意
一个关卡只能分配一个游戏模式类。但是,可以将单个游戏模式类分配给多个关卡,以模仿类似的功能和逻辑。
虚幻角色类
Pawn
类,在虚幻引擎中,是可以被玩家或 AI 控制的最基本的角色类。它也在游戏中图形化地代表玩家/机器人。这个类中的代码应该涉及游戏实体的所有内容,包括交互、移动和能力逻辑。玩家在游戏中仍然只能控制一个角色。此外,玩家可以在游戏过程中取消控制一个角色并控制另一个角色。
默认角色
虚幻引擎提供了一个DefaultPawn
类(继承自基本的Pawn
类)。在Pawn
类的基础上,这个类包含了额外的代码,使其能够在世界中移动,就像在游戏的编辑版本中一样。
观战角色
一些游戏提供了观战游戏的功能。比如说,你正在等待朋友完成他们的游戏,然后加入你,所以你可以先观战他们的游戏。这使你能够观察玩家正在玩的游戏,通过一个可以移动的摄像头来观察玩家或游戏。一些游戏还提供了观战模式,可以回到过去,展示游戏中发生的特定动作或游戏中的任何时间点。
顾名思义,这是一种特殊类型的角色,提供了观战游戏的示例功能。它包含了所有基本工具(如观战角色移动组件)来实现这一点。
虚幻引擎玩家控制器类
玩家控制器类可以被视为玩家。它本质上是角色的灵魂。玩家控制器接收用户输入,并将其传递给角色和其他类,以便玩家与游戏进行交互。然而,在处理这个类时,您必须注意以下几点:
-
与角色不同,一个关卡中只能有一个玩家控制器代表玩家。(就像当你乘坐电梯时。在电梯内,你只能控制那部电梯,但你可以离开它并进入另一部电梯来控制它。)
-
玩家控制器在整个游戏中持续存在,但角色可能不会(例如,在战斗游戏中,玩家角色可能会死亡并重生,但玩家控制器仍然保持不变)。
-
由于角色的临时性和玩家控制器的永久性,开发人员需要考虑应该将哪些代码添加到哪个类中。
让我们通过下一个练习更好地理解这一点。
练习 2.04:设置游戏模式、玩家控制器和角色
这个练习将使用我们在练习 2.01中创建的空项目。我们将向游戏中添加我们的游戏模式、玩家控制器和Pawn
类,并测试我们的代码是否在蓝图中工作。
以下步骤将帮助您完成这个练习:
-
打开我们在练习 2.01中创建的项目,创建一个空的 C++项目。
-
在
内容浏览器
中右键单击,然后选择蓝图类
。 -
在
所有类
部分,找到并选择游戏模式
类:
图 2.16:选择游戏模式类
-
将其命名为
BP_MyGameMode
。 -
重复步骤 2-4,并在
常见类
部分选择Pawn
类,如前面的屏幕截图所示。将此类的名称设置为BP_MyPawn
。 -
重复步骤 2-4,并在
常见类
部分选择玩家控制器
类,如前面的屏幕截图所示。将此类的名称设置为BP_MyPC
:
图 2.17:游戏模式、角色和玩家控制器名称
- 打开
BP_MyGameMode
,并打开事件图
标签:
图 2.18:蓝图中的事件图标签
- 左键单击并从
Event BeginPlay
节点中的白色引脚拖动,然后释放左鼠标按钮以获得选项
菜单。键入print
并在列表中选择突出显示的print
节点:
图 2.19:打印字符串节点(蓝图)
-
在
In String
参数下放置的结果Print String
节点中,键入My Game Mode has started!
。 -
现在,按顶部菜单栏上的
编译
和保存
按钮。 -
重复步骤 7-10,分别为
BP_MyPawn
和BP_MyPC
类设置In String
参数为My Pawn has started!
和My PC has started!
。 -
最后,打开
World Settings
选项卡,在Game Mode
部分,使用下拉菜单将GameMode Override
,Default Pawn Class
和Player Controller Class
选项设置为我们各自的类:
图 2.20:世界设置和游戏模式设置
- 单击
播放
以播放游戏,并在顶部看到三个打印语句。这意味着当前的GameMode Override
,Default Pawn Class
和Player Controller Class
选项已设置为您指定的类,并正在运行它们的代码:
图 2.21:输出打印
注意
您可以在 GitHub 的Chapter02
-> Exercise2.04
-> Ex2.04-Completed.rar
目录中找到已完成的练习代码文件,链接如下:packt.live/3k7nS1K
提取.rar
文件后,双击.uproject
文件。您将看到一个提示,询问是否要立即重建?
。点击该提示上的是
,以便它可以构建必要的中间文件,之后应该会自动在虚幻编辑器中打开项目。
现在您已经了解了虚幻中的基本类以及它们的工作原理,在下一节中,我们将看一下动画,涉及到哪些过程,以及它们是如何完成的。接下来我们将进行一次练习。
动画
动画对于为游戏增添生动和丰富是至关重要的。出色的动画是区分普通游戏和优秀游戏的主要因素之一。视觉保真度是保持玩家对游戏兴奋和沉浸的关键,因此动画是虚幻引擎中创建的所有游戏和体验的核心部分。
注意
本章旨在介绍动画基础知识。对动画的更深入探讨将在第十三章,混合空间 1D,按键绑定和状态机中进行。
动画蓝图
动画蓝图是一种特定类型的蓝图,允许您控制骨骼网格的动画。它为用户提供了一个专门用于动画相关任务的图表。在这里,您可以定义计算骨架姿势的逻辑。
注意
骨骼网格是一种基于骨骼的网格,具有骨骼,所有这些骨骼汇集在一起形成网格,而静态网格(顾名思义)是一种不可动画的网格。骨骼网格通常用于角色和逼真的对象(例如玩家英雄),而静态网格用于基本或无生命的对象(例如墙壁)。
动画蓝图提供两种类型的图表:EventGraph
和AnimGraph
。
事件图
动画蓝图中的事件图提供了与动画相关的设置事件,正如我们在第一章,虚幻引擎介绍中学到的,可以用于变量操作和逻辑。事件图主要用于在动画蓝图中更新混合空间值,从而驱动AnimGraph
中的动画。这里主要使用的常见事件如下:
-
**蓝图初始化动画:**用于初始化动画。
-
**蓝图更新动画:**此事件在每一帧执行,使开发人员能够根据需要执行计算并更新其值:
图 2.22:动画事件图
在上述截图中,您可以看到默认的事件图。这里有事件蓝图更新动画
和尝试获取所有者
节点。您创建了新节点并将它们附加到图中,以完成练习 2.04中的一些有意义的任务,设置游戏模式、玩家控制器和模型。
动画图
动画图专门负责播放动画,并在每帧基础上输出骨架的最终姿势。它为开发人员提供了执行不同逻辑的特殊节点。例如,混合节点接受多个输入,并用于决定当前在执行中使用哪个输入。这个决定通常取决于一些外部输入(如 alpha 值)。
动画图通过评估节点,按照节点上的执行引脚之间的执行流程来工作。
在下面的截图中,您可以看到图上有一个单独的输出姿势
节点。这是动画的最终姿势输出,将在游戏中的相关骨骼网格上可见。我们将在练习 2.05中使用这个:
图 2.23:动画 AnimGraph
状态机
您已经学会了如何设置动画节点和逻辑,但缺少一个重要组件。谁决定何时播放或执行特定的动画或逻辑?这就是状态机的作用。例如,玩家可能需要从蹲姿转换到站立姿势,因此需要更新动画。代码将调用动画蓝图,访问状态机,并让它知道动画的状态需要改变,从而实现平滑的动画过渡。
状态机由状态和规则组成,可以被认为是描述动画状态的状态。状态机在特定时间总是处于一个状态。当满足某些条件(由规则定义)时,就会从一个状态转换到另一个状态。
过渡规则
每个过渡规则都包含一个名为Result
的布尔节点。如果布尔值为 true,则可以发生过渡,反之亦然:
图 2.24:过渡规则
混合空间
当您提供一堆动画时,您可以创建一个状态机并运行这些动画。然而,当您需要从一个动画过渡到另一个动画时,会出现问题。如果您简单地切换动画,它会出现故障,因为新动画的起始姿势可能与旧动画的结束姿势不同。
混合空间是用于根据它们的 alpha 值在不同动画之间进行插值的特殊资产。这反过来消除了故障问题,并在两个动画之间进行插值,导致动画的快速和平滑变化。
混合空间可以在一维中创建,称为混合空间 1D,或者在二维中创建,称为混合空间。这些根据一个或两个输入混合任意数量的动画。
练习 2.05:创建模特动画
现在您已经了解了大部分与动画相关的概念,我们将通过为默认模特添加一些动画逻辑来进行实际操作。我们将创建一个混合空间 1D、一个状态机和动画逻辑。
我们的目标是创建角色的奔跑动画,从而深入了解动画的工作原理,以及它们如何与 3D 世界中的实际角色绑定。
以下步骤将帮助您完成此练习:
- 下载并提取
Chapter02
->Exercise2.05
->ExerciseFiles
目录中的所有内容,这些内容可以在 GitHub 上找到。您可以将其提取到您在计算机上使用的任何目录中。
注意
ExerciseFiles
目录可以在 GitHub 上找到,链接如下:packt.live/32tIFGJ
。
-
双击
CharAnim.uproject
文件以启动项目。 -
按“播放”。使用键盘的W、A、S、D键进行移动,使用空格键进行跳跃。请注意,目前模特身上没有动画。
-
在“内容”文件夹中,浏览到“内容” -> “模特” -> “动画”。
-
右键单击“内容”文件夹,从“动画”部分选择“混合空间 1D”。
-
选择
UE4_Mannequin_Skeleton
。 -
将新创建的文件重命名为
BS_IdleRun
。 -
双击
BS_IdleRun
以打开它。 -
在“资产详细信息”选项卡中,在“轴设置”部分,展开“水平轴”部分,将“名称”设置为“速度”,将“最大轴值”设置为
375.0
:
图 2.25:混合空间 1D 轴设置
-
转到“样本插值”部分,并将“每秒目标权重插值速度”设置为
5.0
。 -
将
ThirdPersonIdle
、ThirdPersonWalk
和ThirdPersonRun
动画分别拖放到图表中:
图 2.26:混合空间预览器
- 在“资产详细信息”选项卡中,在“混合样本”中,设置以下变量值:
图 2.27:混合样本
-
单击“保存”并关闭此“资产”。
-
在“内容”文件夹内右键单击,从“动画”部分选择“动画蓝图”。
-
在“目标骨骼”部分,选择
UE4_Mannequin_Skeleton
,然后单击“确定”按钮:
图 2.28:创建动画蓝图资产
-
将文件命名为
Anim_Mannequin
,然后按Enter。 -
双击新创建的
Anim_Mannequin
文件。 -
接下来,转到“事件图”选项卡。
-
通过在左下角的变量部分单击
+
图标创建一个名为IsInAir?
的布尔变量。确保分配正确的类型:
图 2.29:添加变量
-
创建一个名为
Speed
的浮点变量。 -
拖动“尝试获取所有者”返回值节点,并输入“IsValid”。选择底部的一个:
图 2.30:事件图 IsValid 节点
- 将“事件蓝图更新动画”节点的
Exec
引脚连接到“IsValid”节点:
图 2.31:连接节点
-
从“尝试获取所有者”节点,使用“获取移动组件”节点。
-
从步骤 22中获得的节点中,获取
Is Falling
节点,并将布尔返回值连接到Is in Air?
布尔的“设置”节点。将SET
节点的执行引脚与“IsValid”执行引脚连接:
图 2.32:Is in Air 布尔设置
- 从“尝试获取所有者”节点,使用“获取速度”节点,获取其
VectorLength
,并将输出连接到Speed
的“变量设置”节点:
图 2.33:速度布尔设置
-
接下来,转到“动画图”选项卡。
-
在 AnimGraph内的任何位置右键单击,输入“状态机”,然后单击“添加新状态机”:
图 2.34:添加新状态机选项
-
确保选择节点,然后按F2进行重命名为
MannequinStateMachine
。 -
将
MannequinStateMachine
的输出引脚连接到“输出姿势”节点的输入引脚,并单击顶部栏上的编译按钮:
图 2.35:配置状态机结果输出姿势节点
-
双击
MannequinstateMachine
节点以进入状态机。您将看到一个Entry
节点。将连接到它的状态将成为模特的默认状态。在本练习中,这将是我们的“Idle 动画”。 -
在状态机内的空白区域上右键单击,然后从菜单中选择“添加状态”。按下F2将其重命名为
Idle/Run
。 -
从
Entry
文本旁边的图标拖动,将其指向Idle/Run
节点内部,然后释放以连接它:
图 2.36:将添加的状态连接到 Entry
-
双击
Idle/Run
状态以打开它。 -
从右下角的“资产浏览器”菜单中,选择并拖动
BS_IdleRun
动画到图表中。从左侧的“变量”部分获取Speed
变量并连接它,如图所示:
图 2.37:Idle/Run 状态设置
- 通过单击顶部横幅中的面包屑
MannequinStateMachine
返回到MannequinStateMachine
:
图 2.38:状态机导航面包屑
-
从“资产浏览器”菜单中,将
ThirdPersonJump_Start
动画拖放到图表中。将其重命名为Jump_Start
。 -
对
ThirdPersonJump_Loop
和ThirdPerson_Jump
重复步骤 35,并将它们分别重命名为Jump_Loop
和Jump_End
:
图 2.39:状态设置
-
打开
Jump_Start
状态。单击Play ThirdPersonJump_Start
节点。在“设置”部分取消选中“循环动画”。 -
打开
Jump_Loop
状态,单击Play ThirdPersonJump_Loop
节点。将Play Rate
设置为0.75
。 -
打开
Jump_End
状态,单击Play ThirdPerson_Jump
节点。取消选中“循环动画”布尔值。 -
由于我们可以从
Idle/Run
转换到Jump_Start
,因此从Idle/Run
状态拖动并将其放到Jump_Start
状态。同样,Jump_Start
导致Jump_Loop
,然后到Jump_End
,最后回到Idle/Run
。
拖放箭头以设置状态机,如下所示:
图 2.40:状态连接
- 双击
Idle/Run
到Jump_Start
转换规则图标,并将Is in Air?
变量的输出连接到结果:
图 2.41:Idle/Run 到 Jump_Start 转换规则设置
- 打开
Jump_Start
到Jump_Loop
转换规则。获取ThirdPersonJump_Start
的“剩余时间(比率)”节点,并检查其是否小于0.1
。将结果布尔值连接到结果:
图 2.42:Jump_Start 到 Jump_End 转换规则设置
- 打开
Jump_Loop
到Jump_End
转换规则。将Is in Air?
的反向输出连接到结果:
图 2.43:Jump_Loop 到 Jump_End 转换规则设置
- 打开
Jump_End
到Idle/Run
转换规则。获取ThirdPerson_Jump
的“剩余时间(比率)”节点,并检查其是否小于0.1
。将结果布尔值连接到结果:
图 2.44:Jump_End 到 Idle/Run 转换规则设置
-
关闭动画蓝图。
-
在“内容”文件夹中,浏览到“内容”->
ThirdPersonBP
->“蓝图文件夹”,并打开ThirdPersonCharacter
蓝图。 -
在“组件”选项卡中选择
Mesh
:
图 2.45:网格组件
- 在“详细信息”选项卡中,将
Anim Class
设置为您创建的Animation Blueprint
类:
图 2.46:在骨骼网格组件中指定动画蓝图
-
关闭蓝图。
-
再次玩游戏,注意动画。
以下应该是你实现的输出。正如你所看到的,我们的角色正在奔跑,奔跑动画正在显示:
图 2.47:角色奔跑动画
注意
你可以在 GitHub 上找到完整的练习代码文件,在Chapter02
->Exercise2.05
->Ex2.05-Completed.rar
目录下,链接如下:packt.live/3kdIlSL
解压缩.rar
文件后,双击.uproject
文件。你会看到一个提示,询问“是否要立即重建?”。点击该提示上的“是”,这样它就可以构建必要的中间文件,然后自动在虚幻编辑器中打开项目。
通过完成这个练习,你已经了解了如何创建状态机、Blend Space 1D、动画蓝图,以及如何将它们与角色的骨骼网格结合起来。你还处理了播放速率、过渡速度和过渡状态,帮助你理解动画世界是如何紧密联系在一起的。
我们通过理解状态机如何表示和过渡动画状态来开始这一部分。接下来,我们了解了 Blend Space 1D 如何在这些过渡中进行混合。所有这些都由动画蓝图使用,以决定角色当前的动画是什么。现在,让我们在一个活动中将所有这些概念结合起来。
活动 2.01:将动画链接到角色
假设作为虚幻游戏开发者,你已经获得了一个角色骨骼网格和它的动画,并且被要求将它们整合到一个项目中。为了做到这一点,在这个活动中,你将创建一个新角色的动画蓝图、状态机和 Blend Space 1D。通过完成这个活动,你应该能够在虚幻引擎中处理动画,并将它们链接到骨骼网格。
活动项目文件夹包含一个第三人称模板项目,以及一个新角色Ganfault
。
注意
这个角色及其动画是从mixamo.com下载的。这些已经放在我们的 GitHub 存储库的“内容”->Ganfault
文件夹中:packt.live/35eCGrk
Mixamo.com是一个销售带有动画的 3D 角色的网站,类似于一个专门用于 3D 模型的资产市场。它还包含一个免费模型库,以及付费模型。
以下步骤将帮助你完成这个活动:
-
创建一个用于行走/奔跑动画的 Blend Space 1D,并设置动画蓝图。
-
接下来,转到“内容”->
ThirdPersonBP
->“蓝图”,打开ThirdPersonCharacter
蓝图。 -
点击左侧的骨骼网格组件,在右侧的“详细信息”选项卡中,用
Ganfault
替换SkeletalMesh
引用。 -
同样地,更新骨骼网格组件的“动画蓝图”部分,使用你为
Ganfault
创建的动画蓝图。
注意
对于状态机,只实现空闲/奔跑和跳跃状态。
完成这个活动后,行走/奔跑和跳跃动画应该正常工作,如下所示:
图 2.48:活动 2.01 预期输出(左:奔跑;右:跳跃)
注意
此活动的解决方案可以在以下链接找到:packt.live/338jEBx
。
通过完成这个活动,你现在知道如何在虚幻引擎中导航项目、调试代码和处理动画。你还了解了状态机,它代表了动画状态和过渡之间的转换,以及在该过渡中使用的 Blend Spaces 1D。你现在能够根据游戏事件和输入为 3D 模型添加动画。
摘要
总结本章,我们首先学习了如何创建一个空项目。然后,我们了解了文件夹结构以及如何在项目目录中组织文件。之后,我们看了基于模板的项目。我们还学会了如何在代码中设置断点,以便在游戏运行时观察变量值并调试整个对象,这将帮助我们找到并消除代码中的错误。
此外,我们还了解了游戏模式、玩家角色和玩家控制器是虚幻引擎中用于设置游戏流程(代码执行顺序)的相关类,以及它们在项目中的设置方式。
最后,我们转向动画基础知识,并使用状态机、混合空间 1D 和动画蓝图,根据键盘输入使我们的角色在游戏中执行动画(行走/奔跑和跳跃)。
在整个本章中,我们更加熟悉了虚幻引擎中强大的工具,这些工具对游戏开发至关重要。虚幻的游戏模式及其默认类对于在虚幻引擎中制作任何类型的游戏或体验都是必需的。此外,动画为角色赋予生命,并帮助增加游戏内的沉浸感。所有游戏工作室都有动画、角色和游戏逻辑,因为这些是推动任何游戏的核心组件。这些技能将在你的游戏开发之旅中帮助你很多次。
在下一章中,我们将讨论虚幻引擎中的Character
类,它的组件以及如何扩展该类进行额外的设置。你将进行各种练习,然后进行一项活动。
第三章:角色类组件和蓝图设置
概述
本章将重点讨论 C++中的Character
类。您将学习如何在 C++中扩展Character
类,然后通过继承在蓝图中进一步扩展这个新创建的Character
类。您还将处理玩家输入和一些移动逻辑。
在本章结束时,您将能够理解 UE4 中的类继承是如何工作的,以及如何利用它来获得优势。您还将能够使用轴和动作输入映射,这在驱动与玩家相关的输入逻辑中非常关键。
介绍
在上一章中,我们学习了如何创建空项目和导入文件,使用哪种文件夹结构,以及如何处理动画。在本章中,我们将探索一些其他关键工具和功能,这些工具和功能在使用虚幻引擎时会用到。
游戏开发人员经常需要使用一些工具,这些工具可以节省他们构建游戏功能时的时间和精力。虚幻引擎强大的对象继承能力为开发人员提供了更高效的优势。开发人员还可以交替使用 C++和蓝图,并在开发游戏时充分利用它们。
开发人员获得的另一个增值好处是能够扩展代码以供以后在项目中使用。假设您的客户有新的要求,这些要求建立在旧的要求之上(这在大多数游戏工作室都是这样的情况)。现在,为了扩展功能,开发人员只需继承一个类并向其添加更多功能,以快速获得结果。这是非常强大的,在许多情况下都很方便。
在本章中,我们将讨论虚幻Character
类,创建 C++代码,然后在蓝图中扩展它,最后使用它来创建游戏角色。
虚幻角色类
在我们谈论虚幻Character
类之前,让我们简要地谈一下继承的概念。如果您习惯使用 C++或其他类似的语言,您应该已经熟悉这个概念。继承是一个类从另一个类中继承特性和行为的过程。一个 C++类可以被扩展以创建一个新的类 - 派生类 - 它保留了基类的属性,并允许修改这些属性,或者添加新的特性。Character
类就是一个例子。
Character
类是一种特殊类型的 pawn,是虚幻Pawn
类的后代。在扩展Pawn
类的基础上,Character
类默认具有一些移动能力,以及一些输入,可以为角色添加移动。作为标准,Character
类使用户能够让角色在创建的世界中行走、奔跑、跳跃、飞行和游泳。
由于Character
类是Pawn
类的扩展,它包含了所有的 pawn 的代码/逻辑,开发人员可以扩展这个类以添加更多功能。当扩展Character
类时,它的现有组件会作为继承组件传递到扩展类中。(在这种情况下,Capsule 组件、Arrow 组件和 Mesh)。
注意
继承组件无法被移除。它们的设置可以被改变,但添加到基类的组件将始终存在于扩展类中。在这种情况下,基类是Pawn
类,而扩展(或子)类是Character
类。
Character
类提供以下继承组件:
-
Capsule 组件:这是作为“原点”的根组件,其他组件在层次结构中附加到它上面。这个组件也可以用于碰撞,并且以胶囊的形式逻辑地勾勒出许多角色形式(特别是人形角色)。
-
隐藏
当游戏开始时,但可以调整为可见。如果需要,此组件可用于调试和调整游戏逻辑。 -
Character
类。在这里可以设置角色将采取的形式的骨骼网格,以及所有相关变量,包括动画、碰撞等。
大多数开发人员通常更喜欢在 C++中编写游戏和角色逻辑,并将该类扩展到蓝图,以便他们可以执行其他简单的任务,比如将资产连接到类。例如,开发人员可以创建一个从Character
类继承的 C++类,在该类中编写所有移动和跳跃逻辑,然后使用蓝图扩展此类,在其中开发人员可以使用所需的资产(如骨骼网格和动画蓝图)更新组件,并可选择在蓝图中编写其他功能。
扩展 Character 类
当 C++或蓝图继承时,Character
类会被扩展。这个扩展的Character
类将成为Character
类的子类(也称为其父类)。类扩展是面向对象编程的一个强大部分,类可以被扩展到很深的层次和层次结构。
练习 3.01:创建和设置第三人称角色 C++类
在此练习中,您将创建一个基于Character
类的 C++类。您还将初始化将在扩展此Character
类的类的默认值中设置的变量。
以下步骤将帮助您完成此练习:
-
启动 Unreal Engine,选择
Games
类别,然后单击Next
按钮。 -
选择
Blank
,然后单击Next
按钮。 -
选择
C++
作为项目类型,将项目名称设置为MyThirdPerson
,选择适当的项目目录,然后单击Create Project
按钮。 -
右键单击
Content Browser
界面,然后单击New C++ Class
按钮: -
在打开的对话框中,选择
Character
作为类类型,然后单击Next
按钮。 -
将其命名为
MyThirdPersonChar
,然后点击Create Class
按钮。 -
这样做后,Visual Studio 将打开
MyThirdPersonChar.cpp
和MyThirdPersonChar.h
选项卡。
注意
在某些系统上,可能需要以管理员权限运行 Unreal Engine 编辑器,以自动打开新创建的 C++文件的 Visual Studio 解决方案。
- 打开
MyThirdPersonChar.h
选项卡,在GENERATED_BODY()
文本下添加以下代码:
// Spring arm component which will act as a placeholder for the player camera
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = MyTPS_Cam, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
// Follow camera
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = MyTPS_Cam, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera;
在上述代码中,我们声明了两个组件:Camera
本身和Camera boom
,它充当了玩家与摄像机之间的某个距离的占位符。这些组件将在步骤 11中在构造函数中初始化。
- 在
MyThirdPersonChar.h
文件的#include "CoreMinimal.h"
下的包含部分中添加以下内容:
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
- 现在,转到
MyThirdPersonChar.cpp
选项卡,在#include MyThirdPersonChar.h
代码后添加以下包含:
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
在上述代码片段中,代码将相关类添加到类中,这意味着我们现在可以访问其方法和定义。
- 在
AMyThirdPersonChar::AMyThirdPersonChar()
函数中,添加以下行:
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true;
// Create a camera boom (pulls in towards the player if there is a collision)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 300.0f;
CameraBoom->bUsePawnControlRotation = true;
// Create a camera that will follow the character
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
FollowCamera->bUsePawnControlRotation = false;
上述代码片段的最后一行将设置摄像机与角色的旋转绑定。这意味着摄像机应该随着与该角色关联的玩家控制器的旋转而旋转。
- 返回 Unreal Engine 项目,点击顶部栏的
Compile
按钮:
图 3.1:Unreal Editor 顶部栏上的编译按钮
在右下角应该出现Compile Complete!
消息。
注意
您可以在 GitHub 上的Chapter03
-> Exercise3.01
目录中找到已完成的练习代码文件,链接如下:packt.live/3khFrMt
。
解压.rar
文件后,双击.uproject
文件。你会看到一个提示,询问是否要立即重建?
。点击该提示上的是
,这样它就可以构建必要的中间文件,然后应该会自动在 Unreal Editor 中打开项目。
通过完成这个练习,你学会了如何扩展Character
类。你还学会了如何初始化Character
类的默认组件,并且学会了如何在 Unreal Editor 中编译更新的代码。接下来,你将学会如何扩展你在蓝图中创建的 C++类,以及在许多情况下为什么这是可行的。
用蓝图扩展 C++类
如前所述,大多数开发人员将 C++代码逻辑扩展到蓝图中,以便将其与他们将使用的资产联系起来。这样做是为了实现比在代码中查找和设置资产更容易的资产分配。此外,它还使开发人员能够利用强大的蓝图功能,如时间轴、事件和即用型宏,与他们的 C++代码结合使用,以实现在 C++和蓝图一起开发的最大效益。
到目前为止,我们已经创建了一个 C++ Character
类。在其中,我们设置了组件和移动能力。现在,我们想要指定将在我们的类中使用的资产,并添加输入和移动能力。为此,最好是用蓝图进行扩展并在那里设置选项。这就是我们将在接下来的练习中要做的事情。
练习 3.02:用蓝图扩展 C++
在这个练习中,你将学会如何扩展你用蓝图创建的 C++类,以在现有的 C++代码之上添加蓝图代码。你还将添加输入按键绑定,这将负责移动角色。
以下步骤将帮助你完成这个练习:
- 下载并提取
Chapter03
|Exercise3.02
|ExerciseFiles
目录中的所有内容,这些内容可以在 GitHub 上找到。
注意
ExerciseFiles
目录可以在以下链接的 GitHub 上找到:packt.live/2GO0dG8
。
-
浏览到我们在练习 3.01中创建的
MyThirdPerson
项目内的Content
文件夹。 -
复制我们在步骤 1中创建的
MixamoAnimPack
文件夹,并将其粘贴到我们在步骤 2中打开的Content
文件夹目录中,如下图所示:
注意
MixamoAnimPack
资产是通过以下链接从 Epic 市场获得的:www.unrealengine.com/marketplace/en-US/product/mixamo-animation-pack
。
图 3.2:MixamoAnimPack 放置在项目目录中
-
打开项目。在
Content Browser
界面内右键单击,然后点击Blueprint Class
。 -
在
搜索
对话框中输入GameMode
,右键单击与名称匹配的类,然后点击选择
按钮。查看下面的截图:
图 3.3:创建 GameMode 类
-
在步骤 6中创建的蓝图命名为
BP_GameMode
。 -
现在,重复步骤 5。
-
在搜索框中,输入
MyThirdPersonChar
,选择该类,然后右键单击选择
按钮。 -
在步骤 9中创建的蓝图命名为
BP_MyTPC
。 -
在
World Settings
选项卡中,点击GameMode Override
旁边的None
选项,然后选择BP_GameMode
:
图 3.4:在世界设置中指定游戏模式
- 将
Default Pawn Class
设置为BP_MyTPC
:
图 3.5:在游戏模式中指定默认角色类
-
打开
BP_MyTPC
,在左侧的Components
选项卡的层次结构中点击Mesh (Inherited)
组件。 -
在“详细信息”选项卡中,找到“网格”部分,并将“骨骼网格”设置为
Maximo_Adam
。
注意
骨骼网格和动画将在第十三章中深入讨论,混合空间 1D,按键绑定和状态机。
- 在“详细信息”选项卡中,找到“动画”部分,并将“动画类”设置为
MixamoAnimBP_Adam_C
。您会注意到当选择时,此类名称会以_C
结尾。这基本上是 UE4 创建的蓝图的实例。在工作项目/构建中,蓝图通常以这种方式结尾,以区分蓝图类和该类的实例。
图 3.6:设置动画类和骨骼网格
-
从顶部菜单中,转到“编辑”下拉菜单,单击“项目设置”。
-
单击“输入”部分,该部分位于“引擎”部分中:
图 3.7:项目设置的输入部分
- 在“绑定”部分,单击“轴映射”旁边的
+
图标并展开该部分。
注意
动作映射是执行单个按键操作的动作,例如跳跃、冲刺或奔跑,而轴映射是分配的浮点值,将根据用户的按键返回浮点值。这在游戏手柄或 VR 手柄的情况下更相关,其中模拟拇指杆起作用。在这种情况下,它将返回拇指杆状态的浮点值,这对于管理玩家移动或相关功能非常重要。
-
将
NewAxisMapping_0
重命名为MoveForward
。 -
在
MoveForward
部分,单击下拉菜单并选择W
。 -
单击
MoveForward
图标旁边的+
图标以添加另一个字段。 -
将新字段设置为
S
。将其比例设置为-1.0
(因为我们希望使用S
键向后移动)。 -
通过重复步骤 18创建另一个轴映射,命名为
MoveRight
,并添加两个字段——A
为比例-1.0,D
为比例 1.0:
图 3.8:移动轴映射
- 打开
BP_MyTPC
并单击“事件图”选项卡:
图 3.9:事件图标签
- 右键单击图表内任意位置,键入
MoveForward
,并选择第一个节点选项:
图 3.10:MoveForward 轴事件
- 右键单击图表内,搜索“获取控制旋转”,并选择第一个节点选项。
注意
由于与玩家相关联的摄像机可以选择不显示角色的偏航、翻滚或俯仰,“获取控制旋转”给予角色完整的瞄准旋转。这在许多计算中很有用。
-
左键单击并从“获取控制旋转”节点的“返回值”处拖动,搜索“断裂旋转器”,并选择它。
-
右键单击图表内,搜索“创建旋转器”,并选择第一个节点选项。
-
将“断裂旋转器”中的
Z
(偏航)节点连接到“创建旋转器”节点的Z
(偏航)节点。
注意
使“旋转器”创建一个具有俯仰、翻滚和偏航值的旋转器,而断裂旋转器将一个旋转器分解为其组件(翻滚、俯仰和偏航)。
-
左键单击并从“创建旋转器”节点的“返回值”处拖动,搜索“获取前向矢量”,并选择它。
-
左键单击并从“获取前向矢量”节点的“返回值”处拖动,搜索“添加移动输入”,并选择它。
-
将
InputAxis MoveForward
节点中的“轴值”节点连接到“添加移动输入”节点中的“比例值”节点。 -
最后,将
InputAxis MoveForward
节点的白色“执行”引脚连接到“添加移动输入”节点。 -
右键单击图表内,搜索
InputAxis MoveRight
,并选择第一个节点选项。 -
左键单击并从“创建旋转器”节点的“返回值”处拖动,搜索“获取右矢量”,并选择它。
-
从
Get Right Vector
节点的Return Value
处进行左键单击并拖动,搜索Add Movement Input
,并选择它。 -
将
InputAxis MoveRight
节点中的Axis Value
引脚连接到我们在上一步中创建的Add Movement Input
节点中的Scale Value
引脚。 -
最后,将
InputAxis MoveRight
节点中的白色执行
引脚连接到我们在步骤 36中添加的Add Movement Input
节点:
图 3.11:移动逻辑
- 现在,转到
视口
选项卡。在这里,您会看到角色的正面没有指向箭头的方向,并且角色在胶囊组件上方。单击Mesh
组件,选择位于视口顶部的对象平移节点。然后,拖动网格上的箭头进行调整,使脚与胶囊组件底部对齐,并且网格旋转以指向箭头:
图 3.12:平移旋转和比例选择器部分
一旦角色在胶囊中对齐,它将显示如下截图:
图 3.13:在胶囊组件内调整网格
-
在
工具栏
菜单中,点击编译
按钮,然后点击保存
。 -
返回到地图选项卡,点击
播放
按钮以查看游戏中的角色。使用W、A、S和D键来移动。
注意
您可以在 GitHub 上的Chapter03
-> Exercise3.02
目录中找到已完成的练习代码文件,链接如下:packt.live/3keGxIU
。
解压.rar
文件后,双击.uproject
文件。您会看到一个提示询问“是否要立即重建?”。点击该提示上的“是”,这样它就可以构建必要的中间文件,之后应该会自动在虚幻编辑器中打开项目。
通过完成这个练习,您现在能够理解如何使用蓝图扩展 C++代码,以及为什么在许多情况下这对开发人员是有利的。您还学会了如何添加输入映射以及它们如何用于驱动与玩家相关的输入逻辑。
在本章的活动中,您将结合本章前面练习中所学到的技能,并扩展您在第 2.01 活动,将动画链接到角色活动中完成的项目。这将使您能够构建自己创建的蓝图,并了解它如何映射到现实世界的场景。
活动 3.01:在动画项目中使用蓝图扩展 C++角色类
现在,您已经创建了一个 C++类并将其与蓝图扩展,是时候将这两个概念结合到一个真实的场景中了。在这个活动中,您的目标是使我们在第 2.01 活动中的角色,Mixamo 角色动画,在键盘上使用空格键跳跃。但是,您需要从头开始在 C++中创建Character
类,然后稍后将其扩展为蓝图以达到最终目标。
以下步骤将帮助您完成此活动:
-
打开Activity 2.01,Mixamo 角色动画的项目。
-
在 C++中创建一个
Character
类,该类将初始化角色变量,包括与玩家相关联的摄像机。 -
将跳跃输入映射到项目设置中的空格键。
-
使用蓝图扩展创建的 C++类,以添加相关资产和跳跃功能。
预期输出:
当您按下空格键时,角色应该能够跳跃。关卡应该使用扩展了 C++ Character
类的蓝图:
图 3.14:Ganfault 跳跃活动预期输出
注意
此活动的解决方案可在以下网址找到:packt.live/338jEBx
。
通过完成这项活动,您已经了解了在蓝图中扩展 C++代码以实现功能和逻辑的场景。这种 C++和蓝图的结合是游戏开发者在虚幻引擎中创作精湛和独特游戏的最强大工具。
总结
在本章中,您学习了如何创建一个 C++的Character
类,为其添加初始化代码,然后使用蓝图来扩展它以设置资产并添加额外的代码。
结果遵循了 C++代码以及蓝图代码,并可以在任何有意义的场景中使用。
您还学习了如何设置与W、A、S和D键映射的轴映射,以移动玩家(这是许多游戏中默认的移动映射)。您还学习了如何使角色在游戏中跳跃。
在下一章中,您将深入探讨输入映射以及如何在虚幻编辑器中使用移动预览器。这将帮助您创建具有稳定输入映射到游戏和玩家逻辑的游戏。它还将允许您快速测试您的游戏在移动设备上的外观和感觉,所有这些都在虚幻编辑器中完成。
第四章:玩家输入
概述
本章将解决玩家输入的主题。我们将学习如何将玩家的按键或触摸输入与游戏中的动作(如跳跃或移动)关联起来。
在本章结束时,您将了解“动作映射”和“轴映射”,如何创建和修改它们,如何监听每个映射,如何在按下和释放时执行游戏中的动作,以及如何预览您的游戏,就像您在移动设备上玩一样。
介绍
在上一章中,我们创建了一个从Character
类继承的 C++类,并添加了所有必要的Actor
组件,以便能够从该角色的视角看到游戏,并且能够看到角色本身。然后,我们创建了一个从该 C++类继承的“蓝图”类,以便可以直观地设置所有必要的组件。我们还简要了解了动作和轴映射。
在本章中,我们将更深入地讨论这些主题,并涵盖它们在 C++中的使用。我们将了解玩家输入在 UE4 中的工作原理,引擎如何处理输入事件(按键按下和释放),以及我们如何利用它们来控制游戏中的逻辑。
让我们从了解 UE4 如何将玩家按下的键抽象出来开始本章,以便更容易地通知您这些事件。
注意
在本章中,我们将使用我们在上一章中创建的Character
蓝图的另一个版本,称为BP_MyTPC
。本章的版本将具有默认的 UE4 Mannequin 网格,而不是来自 Mixamo 的网格。
输入动作和轴
玩家输入是区分视频游戏与其他娱乐媒体的因素:它们是互动的事实。要使视频游戏具有互动性,必须考虑玩家的输入。许多游戏通过允许玩家控制虚拟角色来实现这一点,该角色根据玩家按下的键和按钮在虚拟世界中行动,这正是我们将在本章中要做的事情。
如今,大多数游戏开发工具都允许您将按键抽象为动作和轴,这使您可以将名称(例如“跳跃”)与多种不同的玩家输入(按下按钮,轻扫摇杆等)关联起来。动作和轴的区别在于,动作用于二进制输入(可以按下或释放的输入,如键盘上的键),而轴用于标量或连续输入(即可以具有一系列值的输入,如摇杆,可以在“x”和“y”轴上从“-1”到1
)。
例如,如果您正在制作一款赛车游戏,在该游戏中,您越拉动游戏手柄的右扳机按钮,汽车就会加速得越快,那将是一个“轴”,因为它的值可以在 0 到 1 之间变化。但是,如果您希望玩家能够暂停游戏,那将是一个动作,因为它只需要知道玩家是否按下了某个特定的键。
通常,当玩家明确按下“空格键”时,使玩家角色跳跃并不是一个很好的主意,而是在按下“跳跃”动作时使玩家跳跃。然后,可以在其他地方编辑此“跳跃”动作的相关键,以便开发人员和玩家都可以轻松更改导致玩家角色跳跃的键。这就是 UE4 允许您指定玩家输入事件的方式(尽管您也可以监听明确的按键,但这通常不是最佳选择)。
打开您的 UE4 项目并转到“项目设置”窗口。您可以通过单击编辑器左上角的“编辑”,然后选择“项目设置…”,或者单击编辑器工具栏中的“设置”,然后选择“项目设置…”来执行此操作。
此窗口将允许您修改与项目相关的多个设置,涵盖各种类别。如果您在Project Settings
的左边缘向下滚动,您应该会在Engine
类别下找到Input
选项,它将带您到项目的输入设置。点击此选项。
这样做时,您应该会看到窗口右边的输入设置,您将能够访问项目的Action Mappings
和Axis Mappings
等内容:
图 4.1:输入设置窗口中可用的 Action 和 Axis Mappings
Action Mappings
属性允许您在项目中指定动作列表(例如跳跃动作)及其对应的键(例如空格键)。
Axis Mappings
允许您做同样的事情,但适用于没有二进制值(按下或释放)而是具有连续值的键,比如控制器上的摇杆,其值可以在x和y轴上从–1
到1
,或者控制器上的扳机按钮,其值可以在0
到1
之间。
例如,考虑 Xbox One 控制器,可以分解为以下部分:
-
左摇杆
,通常用于控制游戏中的移动 -
Dpad
,可用于控制移动,以及具有各种其他用途 -
右摇杆
,通常用于控制相机和视角 -
Face buttons (X, Y, A, and B)
,根据游戏可以有各种用途,但通常允许玩家在游戏世界中执行动作 -
Bumpers and Triggers (LB, RB, LT, and RT)
,可用于瞄准和射击或加速和刹车等动作
如果您愿意,还可以将二进制键设置为轴;例如,为玩家角色的移动设置游戏手柄摇杆(连续键,其值从–1
到1
)和键盘上的两个二进制键(W和S)。
我们将在本章中看看如何做到这一点。
当我们在第一章 虚幻引擎介绍中生成了Third Person
模板项目时,它已经配置了一些输入,包括W、A、S和D键,以及用于移动的左手柄摇杆
,以及用于跳跃的空格键
和游戏手柄底部面
按钮。
现在让我们在下一个练习中添加新的Action
和Axis Mappings
。
练习 4.01:创建跳跃动作和移动轴
在这个练习中,我们将为跳跃动作添加一个新的Action Mapping
,以及为移动动作添加一对新的Axis Mappings
。
要实现这一点,请按照以下步骤进行:
-
打开
Input Settings
菜单。 -
点击
Action Mappings
属性右侧的+
图标以创建一个新的Action Mapping
:
图 4.2:添加新的 Action Mapping
- 这样做时,您应该会看到一个名为
NewActionMapping_0
的新Action Mapping
,映射到None
键(表示它未映射到任何键):
图 4.3:新 Action Mapping 的默认设置
- 将此映射的名称更改为
Jump
,并将与之关联的键更改为空格键
。
要更改与此动作映射的键,您可以点击当前设置为None
键的下拉属性,输入空格键
,并选择第一个选项:
图 4.4:键下拉菜单(顶部),其中选择了空格键(底部)
- 您可以指定当玩家按住修饰键
Shift
、Ctrl
、Alt
或Cmd
时是否要执行此操作,通过勾选它们各自的适当复选框。您还可以通过单击X
图标将此键从Action Mapping
中移除:)
图 4.5:键下拉菜单和指定修饰键的选项以及从这个 Action Mapping 中移除这个键
- 要向
Action Mapping
添加新的键,您可以简单地点击该Action Mapping
名称旁边的+
图标,要完全删除Action Mapping
,您可以点击其旁边的x
图标:
图 4.6:Action Mapping 的名称,旁边是+和 x 图标
现在让我们使用控制器按钮来映射到这个Action Mapping
。
因为大多数游戏手柄的键位非常相似,UE4 使用Gamepad
前缀将它们的大部分键抽象为通用术语。
- 向这个
Action Mapping
添加一个新的键,并将这个新的键设置为Gamepad Face Button Bottom
键。如果您使用的是 Xbox 控制器,这将是A
按钮,如果您使用的是 PlayStation 控制器,这将是X
按钮:
图 4.7:Gamepad Face Button Bottom 键添加到 Jump Action Mapping
现在我们已经设置好了我们的Jump
Action Mapping
,让我们设置我们的Movement Axis Mapping
。
- 点击
Axis Mappings
属性旁边的+
图标,添加一个新的Axis Mapping
。这个新的Axis Mapping
将用于使角色左右移动。将其命名为MoveRight
,并将其分配给Gamepad Left Thumbstick X-Axis
键,以便玩家可以使用左手柄的x轴来使角色左右移动:
图 4.8:MoveRight 轴映射与与之关联的 Gamepad Left Thumbstick X-Axis 键
如果您看到我们分配的键的右侧,您应该看到该键的Scale
属性,该属性将允许您反转轴,使玩家在将拇指杆向右倾斜时向左移动,反之亦然,并增加或减少轴的灵敏度。
为了允许玩家使用键盘上的左右移动键(这些键要么按下要么释放,并不像拇指杆那样具有连续值),我们将不得不添加两个具有反向值的键。
向这个Axis Mapping
添加两个新的键,第一个是D
键,Scale
为1
,第二个是A
键,Scale
为-1
。这将导致玩家按下D
键时角色向右移动,按下A
键时角色向左移动:
图 4.9:MoveRight 轴映射,同时具有 Gamepad 和键盘键
- 在这样做之后,添加另一个名为
MoveForward
的Axis Mapping
,使用Gamepad Left Thumbstick Y-Axis
,W
和S
键,后者的Scale
为-1
。这个轴将用于使角色前后移动:
图 4.10:MoveForward 轴映射
完成了这些步骤后,我们完成了本章的第一个练习,您已经学会了如何在 UE4 中指定Action
和Axis
Mappings
,从而使您可以抽象出哪些键负责哪些游戏内操作。
现在让我们来看看 UE4 如何处理玩家输入并在游戏中进行处理。
处理玩家输入
让我们想象一个情况,玩家按下与“空格键”相关联的Jump动作,使玩家角色跳跃。在玩家按下“空格键”和游戏使玩家角色跳跃之间,有很多事情要连接这两个事件。
让我们看看从一个事件到另一个事件所需的所有步骤:
-
硬件输入:玩家按下“空格键”。UE4 将监听此按键事件。
-
PlayerInput
类:在按键被按下或释放后,这个类将把该按键转换为一个动作或轴。如果有一个与该按键相关联的动作或轴,它将通知所有监听该动作的类,该按键刚刚被按下、释放或更新。在这种情况下,它将知道“空格键”与Jump动作相关联。 -
Player Controller
类:这是第一个接收这些事件的类,因为它用于代表游戏中的玩家。 -
Pawn
类:这个类(因此也是从它继承的Character
类)也可以监听这些事件,只要它们被玩家控制器所控制。如果是这样,它将在该类之后接收这些事件。在本章中,我们将使用我们的Character
C++类来监听动作和轴事件。
现在我们知道 UE4 如何处理玩家输入,让我们来看看DefaultInput.ini
文件以及它的工作原理。
DefaultInput.ini
如果您进入项目的目录,使用文件资源管理器,然后打开其Config
文件夹,您会在其中找到一些.ini
文件,其中之一应该是DefaultInput.ini
文件。顾名思义,这个文件保存了与输入相关的主要设置和配置。
在本章的第一个练习中,我们编辑了项目的“输入”设置,实际上是编辑器在写入和读取DefaultInput.ini
文件。
在您选择的文本编辑器中打开此文件。它包含许多属性,但我们现在要查看的是Action Mappings
和Axis Mappings
列表。在文件末尾附近,您应该看到,例如,Jump动作在此文件中被指定为:
+ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False, bAlt=False,bCmd=False,Key=SpaceBar)
+ActionMappings=(ActionName="Jump",bShift=False,bCtrl=False, bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Bottom)
您还可以看到一些轴被指定,比如MoveRight
轴:
+AxisMappings=(AxisName="MoveRight",Scale=1.000000, Key=Gamepad_LeftX)
+AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=D)
+AxisMappings=(AxisName="MoveRight",Scale=-1.000000,Key=A)
您可以直接编辑此文件以添加、修改和删除Action Mappings
和Axis Mappings
,而不是编辑项目的“输入设置”,尽管这不是一个非常用户友好的方式。请记住,当您将项目打包到可执行文件时,此文件也将可用,这意味着玩家可以根据自己的喜好编辑此文件。
让我们现在看看如何在 C++中监听Action Mappings
和Axis Mappings
。
练习 4.02:监听移动动作和轴
在这个练习中,我们将使用 C++将我们在上一节中创建的动作和轴注册到我们的角色类中,通过将这些动作和轴绑定到我们角色类中的特定函数。
对于Player Controller
或Character
来监听动作和轴,主要的方法是使用SetupPlayerInputComponent
函数注册Action
和Axis
委托。 MyThirdPersonChar
类应该已经有一个声明和实现这个函数。让我们的角色类通过以下步骤监听这些事件:
- 在 Visual Studio 中打开
MyThirdPersonChar
类头文件,并确保有一个名为SetupPlayerInputComponent
的protected
函数的声明,它返回空,并接收一个class UInputComponent* PlayerInputComponent
属性作为参数。这个函数应该被标记为virtual
和override
:
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
- 打开这个类的源文件,并确保这个函数有一个实现:
void AMyThirdPersonChar::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
}
- 在其实现中,首先调用
PlayerInputComponent
属性的BindAction
函数。这个函数允许这个类监听特定的动作,这种情况下是Jump
动作。它接收以下参数:
-
FName ActionName
- 我们想要监听的动作的名称;在我们的情况下是Jump
动作。 -
EInputEvent InputEvent
- 我们想要监听的特定按键事件,可以是按下、释放、双击等。在我们的情况下,我们想要监听按下事件,可以通过使用IE_Pressed
值来指定。 -
UserClass* Object
- 回调函数将在其上调用的对象;在我们的例子中是this
指针。 -
FInputActionHandlerSignature::TUObjectMethodDelegate< UserClass >::FMethodPtr Func
- 这个属性有点啰嗦,但本质上是一个指向当事件发生时将被调用的函数的指针,我们可以通过输入&
后跟类名,后跟::
,后跟函数名来指定。在我们的情况下,我们希望这是属于Character
类的现有Jump
函数,所以我们将用&ACharacter::Jump
来指定它。
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
注意
所有用于监听动作的函数都必须不接收任何参数,除非您使用Delegates
,这超出了本书的范围。
- 为了让角色停止跳跃,您需要复制这一行,然后将新行的输入事件更改为
IE_Released
,被调用的函数更改为Character
类的StopJumping
函数。
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
- 因为我们将使用
InputComponent
类,所以我们需要在源文件的顶部包含它:
#include "Components/InputComponent.h"
- 现在我们正在监听
Jump
动作,并且在执行该动作时使角色跳跃,让我们继续进行其移动。在类的头文件中,添加一个名为MoveRight
的protected
函数的声明,它不返回任何内容,并接收一个float Value
参数。这个函数将在MoveRight
轴的值更新时被调用。
void MoveRight(float Value);
- 在类的源文件中,添加这个函数的实现,我们将首先检查
Controller
属性是否有效(不是nullptr
),以及Value
属性是否不等于0
:
void AMyThirdPersonChar::MoveRight(float Value)
{
if (Controller != nullptr && Value != 0.0f)
{
}
}
- 如果这两个条件都为真,我们将使用
AddMovementInput
函数来移动我们的角色。这个函数的一个参数是角色移动的方向。为了计算这个方向,我们需要做两件事:
- 获取摄像机在z轴(偏航)上的旋转,以便我们根据摄像机的朝向移动角色。为了实现这一点,我们可以创建一个新的
FRotator
属性,俯仰(y轴上的旋转)和翻滚(x轴上的旋转)的值为0
,属性的偏航值为摄像机当前的偏航值。要获取摄像机的偏航值,我们可以调用玩家控制器的GetControlRotation
函数,然后访问它的Yaw
属性。
const FRotator YawRotation(0, Controller-> GetControlRotation().Yaw, 0);
const FVector Direction = UKismetMathLibrary::GetRightVector(YawRotation);
现在我们可以调用AddMovementInput
函数,传递Direction
和Value
属性作为参数。
AddMovementInput(Direction, Value);
- 因为我们将同时使用
KismetMathLibrary
和Controller
对象,所以我们需要在这个源文件的顶部包含它们:
#include "Kismet/KismetMathLibrary.h"
#include "GameFramework/Controller.h"
- 在这个类的
SetupPlayerInputComponent
函数中监听MoveRight
轴,通过调用PlayerInputComponent
属性的BindAxis
函数。这个函数用于监听轴而不是动作,其参数与BindAction
函数的参数之间唯一的区别是它不需要接收EInputState
参数。将"MoveRight"
、this
指针和这个类的MoveRight
函数作为参数传递给这个函数。
PlayerInputComponent->BindAxis("MoveRight", this, &AMyThirdPersonChar::MoveRight);
注意
所有用于监听轴的函数都必须接收一个float
属性作为参数,除非您使用Delegates
,这超出了本书的范围。
现在让我们在这个类中监听MoveForward
轴:
- 在类的头文件中,添加一个类似于
MoveRight
函数的声明,但将其命名为MoveForward
:
void MoveForward(float Value);
- 在类的源文件中,为这个新的
MoveForward
函数添加一个实现。将MoveRight
函数的实现复制到这个新的实现中,但用其GetForwardVector
函数的调用替换KismetMathLibrary
对象的GetRightVector
函数的调用。这将使用表示摄像头面向方向的向量,而不是其右向量,其面向右侧:
void AMyThirdPersonChar::MoveForward(float Value)
{
if (Controller != nullptr && Value != 0.0f)
{
const FRotator YawRotation(0, Controller-> GetControlRotation().Yaw, 0);
const FVector Direction = UKismetMathLibrary::GetForwardVector(YawRotation);
AddMovementInput(Direction, Value);
}
}
- 在
SetupPlayerInputComponent
函数的实现中,复制监听MoveRight
轴的代码行,并将第一个参数替换为"MoveForward"
,将最后一个参数替换为指向MoveForward
函数的指针:
PlayerInputComponent->BindAxis("MoveForward", this, &AMyThirdPersonChar::MoveForward);
-
现在编译您的代码,打开编辑器,并打开您的
BP_MyTPS
蓝图资产。删除InputAction Jump
事件,以及与之连接的节点。对于InputAxis MoveForward
和InputAxis MoveRight
事件也做同样的操作。我们将在 C++中复制这个逻辑,并需要删除其蓝图功能,以便在处理输入时不会发生冲突。 -
现在,播放关卡。您应该能够使用键盘的
W
、A
、S
和D
键或控制器的左摇杆来移动角色,以及使用Spacebar
键或游戏手柄底部按钮
来跳跃:
图 4.11:玩家角色移动
完成了所有这些步骤后,您已经完成了这个练习。现在您知道如何在 UE4 中使用 C++监听Action
和Axis
事件。
注意
您可以使用PlayerInputComponent
属性的BindKey
函数来监听特定的按键,而不是监听特定的Action
或Axis
。该函数接收与BindAction
函数相同的参数,除了第一个参数应该是一个键而不是FName
。您可以使用EKeys
枚举后跟::
来指定键。
现在,我们已经设置了所有必要的逻辑,使我们的角色移动和跳跃,让我们添加负责围绕角色旋转摄像头的逻辑。
围绕角色转动摄像头
摄像头是游戏中非常重要的一部分,因为它决定了玩家在整个游戏过程中看到的内容和方式。对于本项目来说,摄像头允许您不仅看到周围的世界,还可以看到您正在控制的角色。无论角色是否受到伤害、跌落或其他情况,玩家始终知道他们正在控制的角色的状态,并且能够使摄像头面向他们选择的方向是非常重要的。
与每个现代的第三人称游戏一样,我们将始终使摄像头围绕我们的玩家角色旋转。在第二章“使用虚幻引擎”中设置了Camera
和Spring Arm
组件之后,让我们继续添加两个新的“轴映射”,第一个称为Turn
,与Gamepad Right Thumbstick X-Axis
和MouseX
键相关联,第二个称为LookUp
,与Gamepad Right Thumbstick Y-Axis
和MouseY
键相关联,后者的比例为-1
。
这些“轴映射”将用于使玩家向右和向左以及向上和向下查看:
图 4.12:转动和 LookUp 轴映射
现在让我们添加负责根据玩家输入旋转摄像头的 C++逻辑。
转到MyThirdPersonChar
类的SetupPlayerInputComponent
函数实现,并将负责监听MoveRight
轴或MoveForward
轴的行重复两次。在第一行的副本中,将第一个参数更改为"Turn"
,最后一个参数更改为Pawn
类的AddControllerYawInput
函数,而第二行的副本应该将第一个参数设置为"LookUp"
,最后一个参数设置为Pawn
类的AddControllerPitchInput
函数。
这两个函数分别负责围绕z(左右转向)和y(上下查看)轴添加旋转输入:
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
如果您编译了本节中所做的更改,打开编辑器并播放级别,现在您应该能够通过旋转鼠标或倾斜控制器的右摇杆来移动摄像机:
图 4.13:摄像机围绕玩家旋转
这就结束了使用玩家输入围绕玩家角色旋转摄像机的逻辑。在下一个练习中,我们将广泛地了解移动平台,如 Android 和 iOS。
移动平台
由于技术的最新进展,现在大多数人口都可以使用价格实惠的移动设备,如智能手机和平板电脑。这些设备虽然小,但仍具有相当大的处理能力,现在可以做许多像笔记本电脑和台式电脑这样大的设备可以做的事情之一就是玩视频游戏。
因为移动设备比其他设备更实惠和多功能,您有很多人在上面玩游戏。因此,值得考虑为移动平台(如 Android 和 iOS,两个最大的移动应用商店)开发视频游戏。
让我们现在看一下如何在下一个练习中在虚拟移动设备上预览我们的游戏。
练习 4.03:在移动设备上预览
在这个练习中,我们将使用“移动预览”来玩我们的游戏,以了解在移动设备上玩我们的游戏是什么感觉。在这之前,我们必须进入“Android 平台”设置。
请查看以下步骤:
- 打开“项目设置”窗口,并在其左侧边滚动,直到在“平台”类别下找到
Android
选项。单击该选项。您应该会在类别右侧看到以下内容:
图 4.14:Android 平台窗口警告项目当前尚未配置为该平台
- 此警告是在告诉您项目尚未配置为 Android。要更改此设置,请点击红色警告内的“立即配置”按钮。当您这样做时,它应该会变成绿色警告,告诉您平台已配置:
图 4.15:Android 平台窗口通知您项目已为此平台配置
- 完成后,您可以关闭“项目设置”,单击编辑器工具栏中“播放”按钮旁边的箭头,并选择您看到的“移动预览”选项:
图 4.16:播放按钮下的移动预览选项
这将导致引擎开始加载此预览,并编译所有必要的着色器,这应该需要几分钟时间。
完成后,您应该会看到以下内容:
图 4.17:移动预览窗口播放游戏,就像在 Android 设备上一样
这个预览应该看起来与编辑器内的普通预览类似,但有一些显著的区别:
-
视觉保真度已经降低。因为移动平台没有与 PC 和游戏机相同类型的计算能力,所以视觉质量会降低以考虑到这一点。此外,一些高端平台上可用的渲染功能在移动平台上根本不受支持。
-
在屏幕的左下角和右下角添加了两个虚拟摇杆,它们的工作方式类似于控制器,左摇杆控制角色的移动,右摇杆控制摄像机的旋转。
这个窗口就像一个移动屏幕,你的鼠标就是你的手指,所以如果你按住左摇杆并拖动它,这将导致摇杆在屏幕上移动,从而使角色移动,就像下面的截图所示:
图 4.18:使用左虚拟摇杆移动角色
随着这一章的结束,我们学会了如何在 Android 移动平台上预览我们的游戏,并验证其输入是否正常工作。
现在让我们进入下一个练习,我们将添加触摸输入,使玩家角色跳跃。
练习 4.04:添加触摸屏输入
在这个练习中,我们将继续上一个练习,使玩家角色在玩家在触摸屏设备上点击屏幕时开始跳跃。
要向我们的游戏添加触摸屏输入,请按照以下步骤进行:
- 转到
MyThirdPersonChar
类的头文件,并添加两个声明受保护的函数,这两个函数返回空,并接收ETouchIndex::Type FingerIndex
和FVector Location
参数,第一个参数表示触摸屏幕的手指的索引(无论是第一个、第二个还是第三个手指),第二个参数表示触摸屏幕的位置。将其中一个函数命名为TouchBegin
,另一个命名为TouchEnd
:
void TouchBegin(ETouchIndex::Type FingerIndex, FVector Location);
void TouchEnd(ETouchIndex::Type FingerIndex, FVector Location);
- 在
MyThirdPersonChar
类的源文件中,添加这两个函数的实现,其中TouchBegin
函数将调用Jump
函数,而TouchEnd
函数将调用StopJumping
函数。这将导致我们的角色在玩家触摸屏幕时开始跳跃,并在他们停止触摸屏幕时停止跳跃:
void AMyThirdPersonChar::TouchBegin(ETouchIndex::Type FingerIndex, FVector Location)
{
Jump();
}
void AMyThirdPersonChar::TouchEnd(ETouchIndex::Type FingerIndex, FVector Location)
{
StopJumping();
}
- 转到
SetupPlayerInputComponent
函数的实现,并在PlayerInputComponent
的BindTouch
函数中添加两个调用,这将把屏幕被触摸的事件绑定到一个函数。这个函数接收与BindAction
函数相同的参数,除了第一个参数ActionName
。在第一个函数调用中,将输入事件IE_Pressed
、this
指针和这个类的TouchBegin
函数作为参数传递,而在第二个调用中,将输入事件IE_Released
、this
指针和这个类的TouchEnd
函数作为参数传递:
PlayerInputComponent->BindTouch(IE_Pressed, this, &AMyThirdPersonChar::TouchBegin);
PlayerInputComponent->BindTouch(IE_Released, this, &AMyThirdPersonChar::TouchEnd);
- 使用
Mobile Preview
预览游戏,就像我们在上一个练习中所做的那样。如果你用左鼠标按钮点击屏幕中间,玩家角色应该会跳跃:
图 4.19:点击屏幕中间后角色跳跃
随着这一章的结束,我们完成了使我们的角色在玩家触摸屏幕时跳跃的逻辑。现在我们已经学会了如何向我们的游戏添加输入,并将这些输入与游戏内的动作(如跳跃和移动玩家角色)关联起来,让我们通过在下一个活动中从头到尾地向我们的游戏添加一个新的Walk
动作来巩固我们在这一章中学到的知识。
活动 4.01:为我们的角色添加行走逻辑
在当前游戏中,我们的角色在使用移动键时默认奔跑,但我们需要减少角色的速度并使其行走。
因此,在这个活动中,我们将添加逻辑,使我们的角色在按住键盘上的Shift
键或“游戏手柄右侧按钮”键(Xbox 控制器的B
和 PlayStation 控制器的O
)移动时行走。此外,我们还将在移动平台上进行预览。
要做到这一点,请按照以下步骤:
-
通过“项目设置”窗口打开“输入设置”。
-
添加一个名为
Walk
的新Action Mapping
,并将其与“左 Shift”和“游戏手柄右侧按钮”键关联。 -
打开
MyThirdPersonChar
类的头文件,并添加两个返回空值并且不接收参数的protected
函数的声明,分别称为BeginWalking
和StopWalking
。 -
在类的源文件中为这两个函数添加实现。在
BeginWalking
函数的实现中,通过相应地修改CharacterMovementComponent
属性的MaxWalkSpeed
属性,将角色的速度改变为其值的 40%。要访问CharacterMovementComponent
属性,请使用GetCharacterMovement
函数。 -
StopWalking
函数的实现将是BeginWalking
函数的相反,它将使角色的行走速度增加 250%。 -
当按下该动作时,将“行走”动作绑定到
BeginWalking
函数,并在释放时绑定到StopWalking
函数。
按照这些步骤后,您应该能够让您的角色行走,通过按住键盘的左 Shift键或控制器的右侧按钮按钮来减慢速度并略微改变动画。
图 4.20:角色奔跑(左)和行走(右)
- 现在让我们在移动平台上预览我们的游戏,就像我们在练习 4.03中所做的那样,在移动预览中轻轻拖动左摇杆,使我们的角色慢慢行走。结果应该类似于以下屏幕截图:
图 4.21:移动预览中的角色行走
这就结束了我们的活动。 只要玩家按住“行走”动作,我们的角色现在应该能够慢慢地行走。
注意
此活动的解决方案可以在以下网址找到:packt.live/338jEBx
。
总结
在本章中,您已经学会了如何添加、删除和修改Action Mappings
和Axis Mappings
,这在确定哪些键触发特定动作或轴,如何监听它们以及在按下和释放时如何执行游戏逻辑时,给您一些灵活性。
现在您知道如何处理玩家的输入,您可以允许玩家与您的游戏进行交互,并提供视频游戏所广为人知的代理。
在下一章中,我们将从头开始制作我们自己的游戏。 它将被称为“躲避球”,玩家将控制一个角色试图逃离向它投掷躲避球的敌人。 在那一章中,我们将有机会开始学习许多重要的主题,重点是碰撞。