Unreal 游戏开发项目(三)

原文:annas-archive.org/md5/697adf25bb6fdefd7e5915903f33de14

译者:飞龙

协议:CC BY-NC-SA 4.0

第八章:9.音频-视觉元素

概述

在本章中,我们将完成我们在过去四章中一直在努力的基于躲避球的游戏。我们将通过添加音效、粒子效果,并创建另一个关卡来结束本章,这次关卡中玩家必须遵循实际路径才能完成。到本章结束时,您将能够向您的 UE4 项目添加 2D 和 3D 音效,以及粒子效果。

介绍

在上一章中,我们学习了游戏 UI 以及如何创建和添加用户界面(也称为小部件)到屏幕上。

在本章中,我们将学习如何向我们的游戏添加音频和粒子效果。这两个方面都将提高我们游戏的质量,并为玩家提供更加沉浸式的体验。

在视频游戏中,声音可以以声音效果(也称为 SFX)或音乐的形式出现。声音效果使您周围的世界更加真实和生动,而音乐则有助于为您的游戏设定基调。这两个方面对于您的游戏都非常重要。

在竞技游戏中,如《反恐精英:全球攻势》(CS:GO)中,声音也非常重要,因为玩家需要听到他们周围的声音,如枪声和脚步声,以及它们来自哪个方向,以尽可能多地了解他们周围的情况。

粒子效果和音效之所以重要,是因为它们使您的游戏世界更加真实和沉浸。

让我们通过学习 UE4 中的音频工作来开始本章。

UE4 中的音频

任何游戏的基本组成部分之一是声音。声音使您的游戏更加真实和沉浸,这将为您的玩家提供更好的体验。视频游戏通常有两种类型的声音:

  • 2D 声音

  • 3D 声音

2D 声音不考虑听者的距离和方向,而 3D 声音可以根据玩家的位置在音量上升或下降,并在右侧或左侧移动。2D 声音通常用于音乐,而 3D 声音通常用于音效。主要的声音文件类型是.wav 和.mp3。

以下是 UE4 中与音频相关的一些资产和类:

  • “声音基础”:代表包含音频的资产。这个类主要用于 C++和蓝图,用于引用可以播放的音频文件。

  • 声波:代表已导入到 UE4 中的音频文件。继承自“声音基础”。

  • “声音提示”:一个音频资产,可以包含与衰减(随着听者距离变化而音量如何变化)、循环、声音混合和其他与音频相关的功能相关的逻辑。它继承自“声音基础”。

  • “声音类”:允许您将音频文件分组并管理其中一些设置,如音量和音调。一个例子是将所有与音效相关的声音分组到SFX声音类中,将所有角色对话分组到“对话”声音类中,等等。

  • “声音衰减”:允许您指定 3D 声音的行为的资产;例如,它将从哪个距离开始降低音量,它将在哪个距离变得听不见(无法听到),如果音量会随着距离的增加而线性或指数变化等等。

  • 音频组件:允许您管理音频文件及其属性的演员组件。用于设置连续播放声音,如背景音乐。

在 UE4 中,我们可以像导入其他资产一样导入现有的声音:通过将文件从 Windows 文件资源管理器拖放到“内容浏览器”中,或者通过在“内容浏览器”中点击“导入”按钮。我们将在下一个练习中进行这个操作。

练习 9.01:导入音频文件

在这个练习中,您将从计算机中导入一个现有的声音文件到 UE4 中。当躲避球从表面弹起时,将播放此音频文件。

注意

如果您没有音频文件(.mp3 或.wav 文件)可用来完成此练习,您可以在此链接下载.mp3 或.wav 文件:www.freesoundeffects.com/free-track/bounce-1-468901/

将此文件保存为BOUNCE.wav

一旦您有音频文件,请按照以下步骤操作:

  1. 打开编辑器。

  2. 转到“内容浏览器”界面内的“内容”文件夹,并创建一个名为“音频”的新文件夹:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.1:内容浏览器中的音频文件夹

  1. 转到您刚刚创建的“音频”文件夹。

  2. 将您的音频文件导入此文件夹。您可以通过音频文件从“Windows 文件资源管理器”拖放到“内容浏览器”中来执行此操作。

  3. 完成此操作后,应该会出现一个名为您音频文件的新资产,您可以在单击它时听到它:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.2:导入的音频文件

  1. 打开此资产。您应该看到许多可供编辑的属性。但是,我们将仅专注于“声音”类别内的一些属性:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.3:声音资产的设置

以下属性可在“声音”类别中使用:

  • “循环”:此声音在播放时是否循环。

  • “音量”:此声音的音量。

  • “音调”:此声音的音调。音调越高,频率越高,音调越高。

  • “类”:此声音的“声音类”。

我们将更改的唯一属性是“类”属性。我们可以使用 UE4 提供的现有“声音”类之一,但让我们为躲避球创建自己的“声音类”,以便为我们的游戏创建一组新的声音。

  1. 转到“内容浏览器”界面内的“音频”文件夹。

  2. 右键单击,转到“声音”类别(倒数第二个类别),然后转到“类别”类别,选择“声音类”。这将创建一个新的“声音类”资产。将此资产重命名为“躲避球”。

  3. 打开您导入的声音资产,并将其“类”属性设置为“躲避球”:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.4:将类属性更改为躲避球声音类

现在,这个导入的声音资产属于特定的类,您可以将与躲避球相关的其他声音效果分组到同一个“声音类”中,并通过该“声音类”编辑它们的属性,包括“音量”、“音调”和许多其他属性。

有了这个,我们就可以结束我们的练习了。您已经学会了如何将声音导入到您的项目中,以及如何更改它们的基本属性。现在,让我们继续进行下一个练习,在这个练习中,我们将在我们的游戏中每当躲避球从表面弹开时播放声音。

练习 9.02:当躲避球从表面弹开时播放声音

在这个练习中,我们将为我们的DodgeballProjectile类添加必要的功能,以便当躲避球从表面弹开时播放声音。

要做到这一点,请按照以下步骤操作:

  1. 关闭编辑器并打开 Visual Studio。

  2. DodgeballProjectile类的头文件中,添加一个受保护的class USoundBase*属性,名为BounceSound。此属性应该是一个UPROPERTY,并具有EditDefaultsOnly标记,以便可以在蓝图中进行编辑:

// The sound the dodgeball will make when it bounces off of a   surface
UPROPERTY(EditAnywhere, Category = Sound)
class USoundBase* BounceSound;
  1. 完成此操作后,转到DodgeballProjectile类的源文件,并添加一个包含GameplayStatics对象的包含:
#include "Kismet/GameplayStatics.h"
  1. 然后,在类的OnHit函数的实现开始之前,在对DodgeballCharacter类的转换之前,检查我们的BounceSound是否是有效属性(与nullptr不同),以及NormalImpulse属性的大小是否大于600单位(我们可以通过调用其Size函数来访问大小)。

正如我们在第八章用户界面中看到的,NormalImpulse属性表示在被击中后改变躲避球轨迹的方向和大小的力量。我们要检查它的大小是否大于一定数量的原因是,当躲避球开始失去动量并且每秒在地板上反弹多次时,我们不希望每秒播放BounceSound多次;否则,会产生很多噪音。因此,我们将检查躲避球所受的冲量是否大于该数量,以确保这种情况不会发生。如果这两个条件都成立,我们将调用GameplayStatics对象的PlaySoundAtLocation。这个函数负责播放 3D 声音。它接收五个参数:

  • 一个世界上下文对象,我们将作为this指针传递。

  • 一个SoundBase属性,将是我们的HitSound属性。

  • 声音的来源,我们将使用GetActorLocation函数传递。

  • VolumeMultiplier,我们将传递一个值为1。这个值表示播放此声音时音量会高低多少。例如,值为2表示音量会是原来的两倍。

  • PitchMultiplier,表示播放此声音时音调会高低多少。我们将使用FMath对象的RandRange函数传递这个值,该函数接收两个数字作为参数,并返回这两个数字之间的随机数。为了在0.71.3之间随机生成一个数字,我们将使用这些值作为参数调用这个函数。

看一下以下代码片段:

if (BounceSound != nullptr && NormalImpulse.Size() > 600.0f)
{
  UGameplayStatics::PlaySoundAtLocation(this, BounceSound,   GetActorLocation(), 1.0f, FMath::RandRange(0.7f, 1.3f));
}

注意

负责播放 2D 声音的函数也可以从GameplayStatics对象中获得,它被称为PlaySound2D。这个函数将接收与PlaySoundAtLocation函数相同的参数,除了第三个参数,即声音的来源。

  1. 编译这些更改,然后打开虚幻编辑器。

  2. 打开BP_DodgeballProjectile蓝图,转到其Class Defaults选项卡,并将BounceSound属性设置为你导入的声音资产:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.5:将 BounceSound 属性设置为我们导入的声音

  1. 再次玩这个关卡,进入敌人角色的视线。你应该注意到每当敌人角色投掷的躲避球击中墙壁或地板(而不是玩家角色)时,会播放不同音调的声音:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.6:玩家角色导致敌人角色投掷躲避球

如果这样做成功了,恭喜你——你已经成功使用 UE4 播放了声音!如果你听不到声音,确保它是可听到的(它有一个你可以听到的音量级别)。

然而,你可能会注意到的另一件事是,无论角色与反弹的躲避球的距离如何,声音总是以相同的音量播放:声音不是以 3D 方式播放,而是以 2D 方式播放。要在 UE4 中以 3D 方式播放声音,我们必须学习关于声音衰减资产的知识。

声音衰减

要在 UE4 中以 3D 方式播放声音,你必须创建一个声音衰减资产,就像我们在本章的第一节中提到的那样。声音衰减资产将让你指定当声音与听者的距离增加时,你希望特定声音如何改变音量。看一下以下示例。

打开虚幻编辑器,转到内容浏览器界面内的Audio文件夹,右键单击,转到声音类别,并选择声音衰减。将这个新资产命名为BounceAttenuation

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.7:创建声音衰减资产

打开这个BounceAttenuation资产。

声音衰减资产有许多设置;然而,我们主要关注衰减距离部分的一些设置:

  • 内半径:这个float属性允许我们指定声音开始降低音量的距离。如果声音在小于这个值的距离播放,音量不会受到影响。将此属性设置为200单位。

  • 衰减距离:这个浮点属性允许我们指定声音变得听不见的距离。如果声音在大于这个值的距离播放,我们将听不到它。声音的音量将根据其与听者的距离以及它是更接近内半径还是衰减距离而变化。将此属性设置为1500单位:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.8:声音衰减资产设置

将其视为玩家周围的两个圆,较小的圆是内圆(半径值为内半径),较大的圆是衰减圆(半径值为衰减距离)。如果声音起源于内圆内部,则以全音量播放,而起源于衰减圆外部的声音则不会播放。

注意

您可以在这里找到有关声音衰减资产的更多信息:

docs.unrealengine.com/en-US/Engine/Audio/DistanceModelAttenuation

现在您已经了解了声音衰减资产,让我们继续下一个练习,我们将把躲避球弹起时播放的声音变成 3D 声音。

练习 9.03:将弹跳声音变成 3D 声音

在这个练习中,我们将把上一个练习中添加的躲避球弹起时播放的声音变成 3D 声音。这意味着当躲避球从地面弹起时播放的声音将根据其与玩家的距离而音量有所变化。我们这样做是为了当躲避球远离时,声音音量会很低,而当它靠近时,音量会很高。

要使用我们在上一节中创建的BounceAttenuation资产,请按照以下步骤进行:

  1. 转到DodgeballProjectile的头文件,并添加一个名为BounceSoundAttenuationprotected class USoundAttenuation*属性。这个属性应该是一个UPROPERTY,并且有EditDefaultsOnly标记,以便可以在蓝图中进行编辑:
// The sound attenuation of the previous sound
UPROPERTY(EditAnywhere, Category = Sound)
class USoundAttenuation* BounceSoundAttenuation;
  1. 转到DodgeballProjectile类的源文件中的OnHit函数的实现,并向PlaySoundAtLocation函数的调用添加以下参数:
  • StartTime,我们将传递一个值为0。这个值表示声音开始播放的时间。如果声音持续 2 秒,我们可以通过传递值1使这个声音从其 1 秒标记开始。我们传递一个值0,以便从头开始播放声音。

  • SoundAttenuation,我们将传递我们的BounceSoundAttenuation属性:

UGameplayStatics::PlaySoundAtLocation(this, BounceSound,   GetActorLocation(), 1.0f, 1.0f, 0.0f,   BounceSoundAttenuation);

注意

尽管我们只想传递额外的SoundAttenuation参数,但我们也必须传递所有其他在它之前的参数。

  1. 编译这些更改,然后打开编辑器。

  2. 打开BP_DodgeballProjectile蓝图,转到其类默认选项卡,并将BounceSoundAttenuation属性设置为我们的BounceAttenuation资产:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.9:将 BoundSoundAttenuation 属性设置为 BounceAttenuation 资产

  1. 再次播放关卡并进入敌人角色的视线范围。您现在应该注意到,每当敌人角色投掷的躲避球击中墙壁或地板时播放的声音会根据距离的不同以不同的音量播放,并且如果躲避球远了,您将听不到它:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.10:玩家角色使敌人角色投掷躲避球

有了这个,我们可以结束这个练习。您现在知道如何使用 UE4 播放 3D 声音。我们将在下一个练习中为我们的游戏添加背景音乐。

练习 9.04:为我们的游戏添加背景音乐

在这个练习中,我们将为我们的游戏添加背景音乐。我们将通过创建一个带有音频组件的新 Actor 来实现这一点,正如我们之前提到的,这是适合播放背景音乐的。要实现这一点,请按照以下步骤进行:

  1. 下载位于packt.live/3pg21sQ的音频文件,并将其导入到Content Browser界面的“音频”文件夹中,就像我们在“练习 9.01”、“导入音频文件”中所做的那样。

  2. 右键单击Content Browser界面内部,并使用Actor类作为其父类创建一个新的 C++类。将这个新类命名为MusicManager

  3. 当为这个类生成文件并且 Visual Studio 自动打开时,关闭编辑器。

  4. MusicManager类的头文件中,添加一个名为AudioComponent的新的受保护属性,类型为class UAudioComponent*。将其设置为UPROPERTY,并添加VisibleAnywhereBlueprintReadOnly标签:

UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class UAudioComponent* AudioComponent;
  1. MusicManager类的源文件中,添加AudioComponent类的包含:
#include "Components/AudioComponent.h"
  1. 在这个类的构造函数中,将bCanEverTick属性更改为false
PrimaryActorTick.bCanEverTick = false;
  1. 在这一行之后,添加一个新的行,通过调用CreateDefaultSubobject函数并将UAudioComponent类作为模板参数和"Music Component"作为普通参数传递来创建AudioComponent类:
AudioComponent =   CreateDefaultSubobject<UAudioComponent>(TEXT("Music   Component"));
  1. 进行这些更改后,编译您的代码并打开编辑器。

  2. 转到Content Browser界面中的ThirdPersonCPP -> Blueprints文件夹,并创建一个从MusicManager类继承的新蓝图类。将其命名为BP_MusicManager

  3. 打开这个资产,选择它的“音频”组件,并将该组件的“声音”属性设置为您导入的声音:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.11:更新声音属性

  1. BP_MusicManager类的实例拖入关卡中。

  2. 播放关卡。您应该注意到游戏开始时音乐开始播放,并且当它到达结尾时也应该自动循环播放(这是通过音频组件实现的)。

注意

音频组件将自动循环播放它们正在播放的任何声音,因此不需要更改该声音资产的“循环”属性。

完成所有这些步骤后,我们已经完成了这个练习。您现在知道如何为您的游戏添加简单的背景音乐了。

现在,让我们进入下一个话题,即粒子系统。

粒子系统

让我们谈谈许多视频游戏中非常重要的另一个元素:粒子系统。

在视频游戏术语中,粒子实质上是 3D 空间中可以用图像表示的位置。粒子系统是许多粒子的集合,可能具有不同的图像、形状、颜色和大小。在下图中,您将找到在 UE4 中制作的两个粒子系统的示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.12:UE4 中的两个不同的粒子系统

左侧的粒子系统应该是电火花,可能来自被切割并且现在处于短路状态的电缆,而右侧的粒子系统应该是火。虽然左侧的粒子系统相对简单,但您可以看出右侧的粒子系统内有多种类型的粒子,这些粒子可以组合在同一个系统中。

注意

UE4 有两种不同的工具用于创建粒子系统:CascadeNiagara。Cascade 是自 UE4 开始就存在的工具,而 Niagara 是一个更近期和复杂的系统,自 2020 年 5 月以来才成熟可用,截至虚幻引擎版本 4.25。

在 UE4 中创建粒子系统超出了本书的范围,但建议您使用 Niagara 而不是 Cascade,因为它是引擎的最新添加。

在本章中,我们将只使用已经包含在 UE4 中的粒子系统,但如果您想创建自己的粒子系统,这些链接将为您提供有关 Cascade 和 Niagara 的更多信息:

Cascade:docs.unrealengine.com/en-US/Engine/Rendering/ParticleSystems/Cascade

www.youtube.com/playlist?list=PLZlv_N0_O1gYDLyB3LVfjYIcbBe8NqR8t

Niagara:docs.unrealengine.com/en-US/Engine/Niagara/EmitterEditorReference/index.html

docs.unrealengine.com/en-US/Engine/Niagara/QuickStart

我们将在下一个练习中学习如何将粒子系统添加到我们的游戏中。在本章中,我们将简单地使用已经由 UE4 团队制作的现有粒子系统。

练习 9.05:当躲避球击中玩家时生成一个粒子系统

在这个练习中,我们将了解如何在 UE4 中生成一个粒子系统。在这种情况下,当敌人投掷的躲避球击中玩家时,我们将生成一个explosion粒子系统。

为了实现这一点,请按照以下步骤:

  1. 关闭编辑器,打开 Visual Studio。

  2. DodgeballProjectile类的头文件中,添加一个受保护的class UParticleSystem*属性,名为HitParticles

UParticleSystem类型是 UE4 中的粒子系统的指定。确保将其设置为UPROPERTY并给予EditDefaultsOnly标签,以便可以在蓝图类中进行编辑:

// The particle system the dodgeball will spawn when it hits   the player
UPROPERTY(EditAnywhere, Category = Particles)
class UParticleSystem* HitParticles;
  1. DodgeballProjectile类的源文件中,在其OnHit函数的实现中。在调用Destroy函数之前,检查我们的HitParticles属性是否有效。如果有效,调用GameplayStatics对象的SpawnEmitterAtLocation函数。

此函数将生成一个将播放我们传递的粒子系统的角色。它接收以下参数:

  • 一个World对象,我们将使用GetWorld函数传递。

  • 一个UParticleSystem*属性,它将是我们的HitParticles属性。

  • 将播放粒子系统的角色的FTransform,我们将使用GetActorTransform函数传递:

if (HitParticles != nullptr)
{
  UGameplayStatics::SpawnEmitterAtLocation(GetWorld(),   HitParticles, GetActorTransform());
}

注意

虽然我们在这个项目中不会使用它,但与生成粒子系统相关的另一个函数来自GameplayStatics对象,即SpawnEmitterAttached函数。此函数将生成一个粒子系统并将其附加到一个角色,如果您想要,例如,使一个移动的物体着火,以便粒子系统始终保持附加到该物体,这可能会有用。

  1. 编译这些更改,然后打开编辑器。

  2. 打开BP_DodgeballProjectile蓝图,转到其Class Defaults选项卡,并将HitParticles属性设置为P_Explosion粒子系统资产:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.13:将 HitParticles 属性设置为 P_Explosion

  1. 现在,播放关卡,让您的玩家角色被躲避球击中。现在您应该看到爆炸粒子系统正在播放:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.14:当躲避球击中玩家时播放的爆炸粒子系统

这就结束了这个练习。现在你知道如何在 UE4 中播放粒子系统。粒子系统将为您的游戏增添视觉效果,使其在视觉上更具吸引力。

在下一个活动中,我们将通过在躲避球击中玩家时播放声音来巩固我们在 UE4 中播放音频的知识。

活动 9.01:当躲避球击中玩家时播放声音

在这个活动中,我们将创建逻辑,负责在玩家角色被躲避球击中时每次播放声音。在视频游戏中,以多种方式向玩家传递关键信息非常重要,因此除了改变玩家角色的生命值条外,当玩家被击中时我们还将播放声音,以便玩家知道角色正在受到伤害。

要做到这一点,请按照以下步骤进行:

  1. 将一个声音文件导入到内容浏览器界面内的Audio文件夹中,该声音文件将在玩家角色被击中时播放。

注意

如果您没有声音文件,您可以使用www.freesoundeffects.com/free-track/punch-426855/上提供的声音文件。

  1. 打开DodgeballProjectile类的头文件。添加一个SoundBase*属性,就像我们在练习 9.02中所做的那样,当躲避球从表面弹开时播放声音,但这次称其为DamageSound

  2. 打开DodgeballProjectile类的源文件。在OnHit函数的实现中,在你伤害了玩家角色并在调用Destroy函数之前,检查DamageSound属性是否有效。如果有效,调用GameplayStatics对象的PlaySound2D函数(在练习 9.02中提到,当躲避球从表面弹开时播放声音),将thisDamageSound作为该函数调用的参数。

  3. 编译您的更改并打开编辑器。

  4. 打开BP_DodgeballProjectile蓝图,并将其DamageSound属性设置为您在本活动开始时导入的声音文件。

当您播放关卡时,您应该注意到每当玩家被躲避球击中时,您将听到您导入的声音被播放:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.15:当玩家角色被击中时应该播放声音

完成了这些步骤后,您已经完成了这个活动,并巩固了在 UE4 中播放 2D 和 3D 声音的使用。

注意

此活动的解决方案可以在以下网址找到:packt.live/338jEBx

现在,让我们通过学习一些关于关卡设计概念来结束本章。

关卡设计

第五章线性跟踪,与我们的躲避球游戏相关,我们已经添加了相当多的游戏机制和游戏机会,以及一些视听元素,所有这些都在本章中处理。现在我们有了所有这些游戏元素,我们必须将它们汇集到一个可以由玩家从头到尾玩的关卡中。为此,让我们学习一些关于关卡设计和关卡布局的知识。

关卡设计是一种特定的游戏设计学科,专注于在游戏中构建关卡。关卡设计师的目标是制作一个有趣的关卡,通过使用为该游戏构建的游戏机制向玩家介绍新的游戏玩法概念,包含良好的节奏(充满动作和轻松的游戏序列的良好平衡),以及更多内容。

为了测试关卡的结构,关卡设计师将首先构建所谓的关卡布局。这是关卡的一个非常简单和简化版本,使用了最终关卡将包含的大部分元素,但只使用简单的形状和几何图形制作。这样做的原因是为了在需要修改关卡的部分时更容易和节省时间:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.16:使用 BSP Brushes 在 UE4 中制作的关卡布局示例

注意

应该注意的是,关卡设计是一种特定的游戏开发技能,值得有一本专门的书来介绍,而实际上也有很多这样的书,但是深入讨论这个话题超出了本书的范围。

在下一个练习中,我们将使用我们在最近几章中构建的机制来构建一个简单的关卡布局。

练习 9.06:构建关卡布局

在这个练习中,我们将创建一个新的关卡布局,其中包含一些结构,玩家将从关卡的某个地方开始,并通过一系列障碍物到达关卡的结尾。我们将使用我们在最近几章中构建的所有机制和对象来制作一个玩家能够完成的关卡。

尽管在这个练习中我们将为您提供一个解决方案,但鼓励您发挥创造力,提出自己的解决方案,因为在这种情况下没有对错之分。

要开始这个练习,请按照以下步骤操作:

  1. 打开编辑器。

  2. 转到ThirdPersonCPP->“内容浏览器”中的“地图”文件夹,复制ThirdPersonExampleMap资产,并将其命名为Level1。您可以通过选择资产并按下Ctrl + W或右键单击资产并选择“复制”(第三个选项)来执行此操作。

  3. 打开新创建的Level1地图。

  4. 删除地图中具有网格的所有对象,除了以下对象:

  • 玩家角色

  • 敌人角色(注意两个角色看起来是一样的)

  • 地板对象

  • 我们创建的墙对象

  • 胜利箱对象

请记住,与照明和声音相关的资产应保持不变。

  1. 通过按下“构建”按钮为Level1建立照明。该按钮位于编辑器窗口顶部的“工具栏”中,“播放”按钮的左侧。

  2. 在您按照这些步骤操作后,您应该有一个空的地板,只有您在这个关卡中需要的对象(在步骤 4中提到的对象)。以下是在您分别按照步骤 4 和 5之后的Level1地图之前和之后的情况:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.17:删除所需对象之前

一旦你删除了对象,你的地板应该如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.18:删除所需对象后

因为建立一个关卡,即使是一个简单的关卡,也需要很多步骤和指示,所以我们将简单地展示一些可能的关卡截图,并鼓励您自己想出解决方案。

  1. 在这种情况下,我们只是简单地使用了现有的EnemyCharacterWallGhostWall对象,并将它们多次复制,以创建玩家可以从头到尾穿越的简单布局。我们还移动了VictoryBox对象,使其与新关卡的结束位置匹配:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.19:创建的关卡-等距视图

关卡可以从俯视图中看到如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9.20:创建的关卡-俯视图,玩家角色用箭头标记

一旦你对结果满意,这意味着你已经完成了你的躲避球游戏,现在可以邀请你的朋友和家人来玩,并看看他们的想法。干得好 - 你离掌握游戏开发的艺术又近了一步!

额外功能

在我们结束本章之前,这里有一些建议,关于接下来在这个躲避球项目中你可以做些什么:

  • 使之前创建的普通“墙”类不会阻挡敌人的视线。这样,敌人将始终向玩家投掷躲避球,但仍然会被这堵墙挡住。

  • 添加一个新功能,允许玩家通过“扫描轨迹”概念来可视化敌人角色投掷的躲避球首先会影响到哪里。

  • 添加一种新类型的墙,可以阻挡玩家角色、敌人角色和躲避球,但也会受到躲避球的伤害,并在耗尽生命值时被摧毁。

这个项目的扩展空间是无限的。我们鼓励你运用所学的技能,并进行进一步的研究,为你的游戏添加新功能并增加更多的复杂性。

总结

你现在已经完成了躲避球游戏项目。在本章中,你学会了如何通过播放音频和使用粒子系统来为你的游戏增添亮点。你现在知道如何为你的游戏添加 2D 和 3D 声音,以及一些相关的工具。现在,你可以尝试为你的游戏添加更多的声音效果,比如当敌人角色第一次看到你时的特殊声音效果(比如《合金装备》中的情况)、脚步声音效果或者胜利声音效果。

你还使用了在前几章中制作的所有工具来构建一个关卡,从而汇总了我们在这个项目中构建的所有逻辑。

在下一章中,我们将开始一个新项目:《超级横向卷轴》游戏。在那个项目中,你将接触到诸如增益、可收集物品、敌人人工智能(AI)、角色动画等主题。你将创建一个横向卷轴平台游戏,控制一个角色完成关卡,收集宝石,并使用增益来避开敌人。你将学习的两个最重要的主题是 UE4 的行为树和黑板,它们支持 AI 系统,以及动画蓝图,它允许你管理角色的动画。

第九章:创建一个 SuperSideScroller 游戏

概述

在本章中,我们将为新的SuperSideScroller游戏设置项目。您将了解横向滚动游戏的不同方面,包括强化道具、可收集物品和敌人人工智能,我们将在项目中使用所有这些。您还将了解游戏开发中的角色动画流程,并了解如何操纵我们游戏角色的移动。

在本章结束时,您将能够创建一个横向滚动项目,操纵我们角色的默认模特骨骼,导入角色和动画,并创建角色和动画蓝图。

介绍

到目前为止,我们已经学到了很多关于虚幻引擎、C++编程和一般游戏开发技术和策略的知识。在之前的章节中,我们涵盖了诸如碰撞、追踪、如何在虚幻引擎 4 中使用 C++,甚至蓝图可视化脚本系统等主题。除此之外,我们还获得了关于骨骼、动画和动画蓝图的关键知识,我们将在即将到来的项目中利用这些知识。

对于我们的最新项目SuperSideScroller,我们将使用许多在之前章节中使用过的概念和工具来开发我们的游戏特性和系统。碰撞、输入和 HUD 等概念将是我们项目的重点;然而,我们还将深入研究涉及动画的新概念,以重新创建流行横向滚动游戏的机制。最终项目将是我们迄今为止在本书中学到的一切的结晶。

有无数的横向滚动游戏示例可供参考。最近一些流行的横向滚动游戏包括CelesteHollow KnightShovel Knight,但是横向滚动/平台游戏背后也有悠久而丰富的历史,我们将在本章中讨论。

项目分解

让我们考虑一下著名的超级马里奥兄弟的例子,该游戏于 1985 年在任天堂娱乐系统NES)主机上发布。这款游戏是由任天堂制作,由宫本茂设计。对于不熟悉这个系列的人来说,一般的想法是:玩家控制马里奥,他必须穿越蘑菇王国的许多危险障碍和生物,希望从邪恶的酷霸王鲍斯那里救出桃花公主。

注意

为了更好地理解游戏的运作方式,请随时在supermariobros.io/免费在线玩游戏。整个超级马里奥兄弟系列的更深入的维基可以在这里找到:www.mariowiki.com/Super_Mario_Bros

以下是这种类型游戏的核心特点和机制:

  1. SuperSideScroller游戏将是 3D 而不是纯 2D,我们角色的移动将与马里奥的移动方式完全相同,只支持垂直和水平移动:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.1:2D 和 3D 坐标向量的比较

  1. SuperSideScroller游戏也不例外。有许多不同的游戏,如CelesteHollow KnightSuper Meat Boy,如前所述,都使用了跳跃功能-所有这些都是 2D 的。

  2. 角色强化道具:没有角色强化道具,许多横向滚动游戏会失去混乱感和可重复性。例如,在游戏奥里和失落的森林中,开发者引入了不同的角色能力,改变了游戏的玩法。像三段跳或空中冲刺这样的能力打开了各种可能性,使玩家能够根据其移动能力创建有趣的布局。

  3. 敌方 AI:引入具有各种能力和行为的敌人,以增加玩家的挑战层次,除了通过可用的移动机制单独导航关卡的挑战之外。

注意

游戏中的 AI 可以以哪些方式与玩家互动?例如,在《上古卷轴 V:天际》中,各个城镇和村庄中的 AI 角色可以与玩家进行对话,以阐述世界构建元素,如历史,向玩家出售物品,甚至向玩家提供任务。

  1. SuperSideScroller游戏将允许玩家收集硬币。

现在我们已经评估了我们想要支持的游戏机制,我们可以分解每个机制的功能,以及它如何与我们的SuperSideScroller相关,以及我们需要做些什么来实现这些功能。

玩家角色

当使用虚幻引擎 4 的侧向滚动游戏项目模板时,几乎所有我们想要的角色功能都已经默认给我们了。

注意

在撰写本文时,我们使用的是虚幻引擎版本 4.24.2;使用引擎的其他版本可能会导致编辑器、工具以及后续逻辑的一些差异,因此请记住这一点。

现在,让我们在下一个练习中开始创建我们的项目。

练习 10.01:创建侧向滚动项目并使用角色移动组件

在本练习中,您将使用侧向滚动模板设置虚幻引擎 4。这个练习将帮助您开始我们的游戏。

以下步骤将帮助您完成练习:

  1. 首先,打开 Epic Games Launcher,导航到左侧选项底部的Unreal Engine选项卡,并在顶部选择Library选项。

  2. 接下来,您将收到一个窗口提示您要么打开现有项目,要么创建特定类别的新项目。其中包括游戏类别;选择此选项以进行我们的项目。选择了项目类别后,您现在需要选择项目的模板。

  3. 接下来,点击侧向滚动选项,因为我们希望我们的游戏使用 3D 骨骼网格和动画,而不仅仅是 2D 纹理、翻页书和 Paper2D 工具集的其他功能。

注意

请务必选择正确的侧向滚动选项,因为虚幻引擎 4 有两种类型的侧向滚动项目:侧向滚动2D 侧向滚动

我们将在本练习之后讨论这两种项目模板之间的主要区别。

最后,我们需要设置我们的项目设置。

  1. 选择基于C++的项目,而不是蓝图,以包括入门内容,并将我们的平台选择为桌面/控制台。其余的项目设置可以保留为默认设置。选择位置并命名项目为SuperSideScroller,并将项目保存在您选择的适当目录中。

  2. 应用这些设置后,选择创建项目。当编译引擎完成后,虚幻编辑器和 Visual Studio 都将打开,我们就可以开始了。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.2:虚幻引擎编辑器现在应该已经打开

接下来,我们继续操作默认的SideScroller角色内存在的角色移动组件,并查看这如何影响角色。Character Movement组件只能在Character类中实现,并允许双足化身通过行走跳跃飞行游泳移动。这个组件还具有内置的网络复制功能,这对于多人游戏是必要的。

  1. Content Browser中,导航到/SideScrollerCPP/Blueprints/目录,并找到SideScrollerCharacter蓝图:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.3:在内容浏览器中选择默认的 SideScrollerCharacter 蓝图

  1. 双击蓝图资产以打开蓝图。有时,如果蓝图没有任何图形逻辑,您将看到图 10.4中显示的内容。如果您看到这个,请只需左键单击“打开完整蓝图编辑器”:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.4:当蓝图没有图形逻辑时

  1. 打开角色“蓝图”,我们可以左键单击“组件”选项卡中的“CharacterMovement(继承)”组件,以查看此组件的参数。

  2. 现在,在“详细信息”面板下,我们可以访问数十个影响角色移动的参数。在Character Movement: Walking类别中,我们有Max Walk Speed参数。将此值从600.0f更改为2000.0f

  3. 最后,编译并保存我们的角色蓝图。现在,如果我们在编辑器中播放,我们可以观察到我们的玩家角色移动得有多快:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.5:如果我们在编辑器中播放,我们可以看到我们的角色移动得更快

现在您已经完成了这项练习,亲身体验了对玩家角色移动方式的控制!尝试更改“最大行走速度”的值,并观察这些更改如何影响角色。

侧向滚动与 2D 侧向滚动

让我们在这里花点时间了解“2D 侧向滚动”项目模板和“侧向滚动”模板之间的主要区别。 “2D 侧向滚动”模板使用了基于纸张 2D 系统构建的虚幻引擎 4,利用了基于纹理的动画,通过纹理、精灵和纸张翻书。

注意

有关 Paper2D 的更多详细信息,请参阅以下文档:docs.unrealengine.com/en-US/Engine/Paper2D/index.html

有关 Paper2D 的材料足够多,值得有一本专门的教材,因此我们不会再涉及太多这个主题。然而,“侧向滚动”模板几乎与 2D 版本相同,只是我们使用 3D 动画骨骼而不是 2D 动画。

现在,让我们继续并看看执行我们的第一个活动来操纵玩家角色的跳跃动作。

活动 10.01:使我们的角色跳得更高

在这项活动中,我们将操纵默认的“侧向滚动”角色蓝图中CharacterMovement组件中存在的一个新参数(跳跃),以观察这些属性如何影响我们的角色移动。

我们将实施从练习 10.01中学到的内容,创建侧向滚动项目并使用角色移动组件,并将其应用于如何创建我们的角色强化道具以及角色的一般移动感觉。

以下步骤将帮助您完成这项活动:

  1. 转到SideScrollerCharacter蓝图,并在CharacterMovement组件中找到Jump Z Velocity参数。

  2. 将此参数从默认的1000.0f 更改为2000.0f。

  3. 编译并保存SideScrollerCharacter蓝图,并在编辑器中播放。观察我们的角色使用键盘上的空格键可以跳多高。

  4. 停止在编辑器中播放,返回到SideScrollerCharacter蓝图,并将Jump Z Velocity2000.0f 的值更新为200.0f。

  5. 再次编译并保存蓝图,然后在编辑器中播放,观察角色的跳跃。

预期输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.6:跳跃角色的预期输出

注意

此活动的解决方案可在此处找到:packt.live/338jEBx

现在我们已经完成了这个活动,对于CharacterMovement组件参数的一些更改如何影响我们的玩家角色有了更好的理解。当我们需要给我们的角色基本的移动行为,比如行走速度跳跃 Z 速度时,我们可以在以后使用这些知识来实现我们想要的角色感觉。在继续之前,将跳跃 Z 速度参数恢复到默认值 1000.0f。

在我们项目的后期,当我们开发我们的玩家角色增强道具时,我们也会记住这些参数。

我们横向卷轴游戏的特点

现在让我们花点时间来详细说明我们将要设计的游戏。这些特性中的许多将在后面的章节中实现,但现在是一个好时机来规划项目的愿景。

敌人角色

在玩SuperSideScroller项目时,你应该已经注意到默认情况下没有提供敌人 AI。因此,让我们讨论我们希望支持的敌人类型以及它们的工作方式。我们的SuperSideScroller项目将支持一种敌人类型。

敌人将有一个基本的来回移动模式,并不支持任何攻击;只有与玩家角色碰撞,他们才能造成伤害。然而,我们需要设置敌人 AI 要移动的两个位置,接下来,我们需要决定 AI 是否应该改变位置。他们应该不断在位置之间移动,还是在选择新位置移动之前应该暂停一下?

最后,我们决定我们的 AI 是否应该始终知道玩家的位置。如果玩家进入敌人的一定范围,敌人是否应该知道这一点,并积极地朝着玩家最后所在的位置移动?

第十三章 敌人人工智能中,我们将使用虚幻引擎 4 中可用的工具来开发这种 AI 逻辑。

增强道具

SuperSideScroller游戏项目将支持一种类型的增强道具,即玩家可以从环境中拾取的药水。这种药水增强道具将增加玩家的移动速度和最大跳跃高度。这些效果只会持续很短的时间,然后就会消失。

记住你在练习 10.01 创建横向卷轴项目并使用角色移动组件活动 10.01 使我们的角色跳得更高中实现的内容,关于CharacterMovement组件,你可以开发一个改变角色重力影响的增强道具,这将允许以新的有趣方式穿越关卡和与敌人战斗。

可收集物品

视频游戏中的可收集物品有不同的用途。在某些情况下,可收集物品被用作一种货币,用于购买升级、物品和其他商品。在其他情况下,可收集物品用来提高你的得分或在收集足够的可收集物品时奖励你。对于SuperSideScroller游戏项目,硬币将只有一个目的:给玩家一个目标,尽可能多地收集硬币,而不被敌人摧毁。

让我们分解一下我们可收集物品的主要方面:

  • 可收集物品需要与我们的玩家进行交互;这意味着我们需要使用碰撞检测让玩家收集它,并且为我们的 UI 添加信息。

  • 可收集物品需要一个视觉静态网格表示,以便玩家可以在关卡中识别它。

我们SuperSideScroller项目的最后一个元素是砖块。砖块将为SuperSideScroller游戏提供以下用途:

  • 砖块被用作关卡设计的一个元素。砖块可以用来进入其他无法到达的区域;敌人可以放置在不同高度的砖块上,以提供游戏玩法的变化。

  • 砖块中可以包含可收集的硬币。这给玩家一个动力去尝试并查看哪些方块包含可收集物品,哪些不包含。

HUD(头顶显示)

HUD UI 可以用于根据游戏类型和您支持的机制向玩家显示重要和相关的信息。对于SuperSideScroller项目,将有一个 HUD 元素,它将向玩家显示他们收集了多少个硬币。每当玩家收集一个硬币时,此 UI 将更新,并且当玩家被销毁时将重置为0

现在我们已经列出了这个项目的一些具体内容,我们将继续进行动画流程。

动画步骤

需要明确的是,本书不会涵盖动画制作。我们不会讨论和学习如何使用 3D 软件工具(如 3D Studio Max、Maya 或 Blender)制作动画。然而,我们将学习如何将这些资产导入虚幻引擎,使用引擎内的动画资产,并使用可用的动画工具集来赋予角色生命。

角色动画流程

对于本书的目的,我们只关注 3D 动画以及动画在虚幻引擎 4 中的工作方式;然而,简要讨论许多行业中用于创建角色及其动画的流程是很重要的。

概念阶段

第一阶段是开发我们想要创建并稍后进行动画的角色的概念。这几乎总是以 2D 形式完成,可以手工完成,也可以通过使用诸如 Photoshop 之类的计算机程序完成。对于 3D 建模师来说,有几个关于角色外观和相对大小的参考图,可以使建模过程更加容易。下面,我们看到一个棍人角色在不同姿势下的基本示例。注意角色以不同的方式摆姿势:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.7:一个 2D 角色概念的非常简单的例子

3D 建模阶段

一旦角色概念完成,流程就可以转移到下一个阶段:制作角色的 3D 模型。模型通常是在 3D Studio Max 或 Maya 等程序中制作的,但这些软件相对昂贵,除非您有学生许可证,并且更常用于专业环境中。

不需要详细讨论 3D 建模的复杂性,我们只需要知道 3D 艺术家使用计算机软件来操纵 3D 空间中的点(称为顶点)来创建物体。然后将这些物体雕刻成我们的角色或环境部件的形状。

绑定阶段

一旦最终的角色模型完成,就可以开始绑定过程。通常用于建模角色的软件通常也用于绑定角色。绑定意味着构建一系列形成角色骨架的骨骼。

在人形角色的情况下,我们通常会看到头部、脊柱、臀部、腿部等骨骼;但是骨架的形状可能会因您制作的角色类型而有所不同。大象的骨骼结构与人类完全不同。同一个骨骼结构也可以应用于不同的角色。

动画

一旦我们的角色绑定完成并且有了骨骼层次结构,就该是动画师拿起这个网格并用动画赋予它生命的时候了。

3D 动画,基本上是对骨骼在时间上的操纵。记录骨骼位置、旋转和缩放随时间的变化过程就是动画的结果。动画完成后,我们可以从 3D 软件中导出资产,并将其导入引擎。

资产导出和导入

当我们有了我们的 3D 角色网格,它的骨骼系统和动画,就是时候将这些资产从 3D 软件导出并导入到虚幻引擎 4 中了。重要的是要注意,负责角色、骨骼和动画的艺术家们将不断地将正在进行中的工作资产导入引擎,以更好地了解最终在游戏中的效果。我们将在本章的Activity 10.03导入更多自定义动画以预览角色奔跑及其相关练习中实施这一点。

练习 10.02:探索 Persona 编辑器并操纵默认人体骨骼权重

现在我们对动画流程有了更好的理解,让我们深入了解一下在Side Scroller模板项目中给我们的默认人体骨骼网格。

我们的目标是更多地了解默认骨骼网格和 Persona 编辑器中给我们的工具,以便更好地了解骨骼、骨骼权重和骨骼在虚幻引擎 4 中的工作方式。

以下步骤将帮助您完成练习:

  1. 打开虚幻引擎编辑器,导航到内容浏览器

  2. 导航到/Mannequin/Character/Mesh/文件夹并打开UE4_Mannequin_Skeleton资产:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.8:UE4_Mannequin_Skeleton 资产在此处被突出显示并可见

打开骨骼资产后,我们看到了Persona 编辑器

图 10.9:Persona 编辑器

](https://github.com/OpenDocCN/freelearn-c-cpp-zh/raw/master/docs/gm-dev-pj-ue/img/B16183_10_09.jpg)

图 10.9:Persona 编辑器

让我们简要地解释一下 Persona 的骨骼编辑器:

  • 在左侧(标有 1)我们看到了骨骼层次结构。这是在角色的绑定过程中制作的骨骼。root骨骼,顾名思义,是骨骼层次结构的根。这意味着对这个骨骼的变换将影响层次结构中的所有骨骼。从这里,我们可以选择一个骨骼或一组骨骼,并查看它们在角色网格上的位置。

  • 接下来,我们看到了骨骼网格预览窗口(标有 2)。它显示了我们的角色网格,并且有一些额外的选项,我们可以切换这些选项,以便预览我们的骨骼和权重绘制。

  • 在右侧(标有 3)我们有基本的变换选项,可以修改单个骨骼或骨骼组。还有其他可用的设置,我们将在下一个练习中加以利用。现在我们更了解它是什么以及我们在看什么,让我们看看我们的人体骨骼网格上的实际骨架是什么样子。

  1. 导航到Character,如图 10.10所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.10:角色选项菜单让您能够在网格上显示人体骨骼的能力

  1. 从下拉菜单中选择Bones选项。然后确保选择了All Hierarchy选项。选择此选项后,您将看到人体骨骼网格上方的轮廓骨架渲染在人体模型上方:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.11:骨架叠加在人体骨骼网格上

  1. 现在,隐藏网格,只是预览骨骼层次结构,我们可以禁用Mesh属性:
  • 导航到Character,从下拉菜单中选择Mesh选项。

  • 取消Mesh选项,结果应该如下所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.12:默认角色的骨骼层次结构

为了本练习的目的,让我们切换Mesh可见性,这样我们就可以看到网格和骨骼层次结构。

最后,一起看一下我们默认角色的权重缩放。

  1. 要预览此内容,请转到Character,然后从下拉菜单中选择Mesh选项。然后,在标有Mesh Overlay Drawing的部分底部选择Selected Bone Weight选项:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.13:下拉选项显示人体模型骨骼的选定骨骼权重

  1. 现在,如果我们从层次结构中选择一个骨骼或一组骨骼,我们可以看到每个骨骼如何影响网格的某个区域:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.14:这是 spine_03 骨的权重缩放

您会注意到,当我们预览特定骨骼的权重缩放时,骨骼网格的不同部分会显示一系列颜色。这是权重缩放的视觉显示,而不是数值上的。诸如红色橙色黄色的颜色表示骨骼的权重较大,这意味着这些颜色的高亮区域将受到更大影响。在蓝色绿色青色的区域,它们仍会受到影响,但影响不那么显著。最后,没有高亮叠加的区域将不受选定骨骼的操作影响。请记住骨骼的层次结构,因为即使左臂没有叠加颜色,当您旋转、缩放和移动spine_03骨时,它仍会受到影响,因为手臂是spine_03骨的子级。请参考下面的图像,看看手臂是如何连接到脊柱的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.15:clavicle_l 和 clavicle_r 骨是 spine_03 骨的子级

让我们继续操作人体模型骨骼网格中的一个骨骼,并看看这些变化如何影响其动画。

  1. 在 Persona 编辑器中,左键单击骨骼层次结构中的thigh_l骨:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.16:这里选择了 thigh_l 骨

选择thigh_l骨后,我们清楚地知道权重缩放将如何影响网格的其他部分。此外,由于骨骼的结构,对该骨骼的任何修改都不会影响网格的上半身:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.17:您可以看到,在骨骼层次结构中,大腿骨是骨盆骨的子级

  1. 使用前几章的知识,更改thigh_l骨的本地位置、本地旋转和比例值,以偏移骨骼的变换。下面的图像显示了要使用的值示例。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.18:大腿 _l 值已更新

对骨骼变换进行更改后,您会看到人体模型的左腿完全改变,看起来很荒谬:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.19:人体模型角色的左腿完全改变

  1. 接下来,在Details面板中,转到标有Preview Scene Settings的选项卡。左键单击此选项卡,您将看到新选项,显示一些默认参数和一个Animation部分。

  2. 使用动画部分预览动画以及它们如何受到对骨骼所做更改的影响。对于预览控制器参数,将其更改为使用特定动画选项。通过这样做,将出现一个名为动画的新选项。动画参数允许我们选择与角色骨骼关联的动画来预览。

  3. 接下来,左键单击下拉菜单,选择ThirdPersonWalk动画。

  4. 最后,现在你可以看到模特角色正在播放行走动画,但他们的左腿完全错位和错缩:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.20:模特角色更新动画的预览

在继续之前,请确保将thigh_l骨骼恢复到其原始本地位置、本地旋转和比例;否则,向前进行的动画将不会看起来正确。

现在,您已经完成了我们第二项练习的最后部分,亲身体验了骨骼对角色和动画的影响。

现在,让我们继续进行第二项活动,操作模特角色的不同骨骼并观察应用不同动画的结果。

活动 10.02:骨骼操作和动画

对于这项活动,我们将实践我们对默认模特角色上的骨骼操作如何影响骨骼上的动画的知识。

以下步骤将帮助您完成此活动:

  1. 选择将影响整个骨骼的骨骼。

  2. 更改此骨骼的比例,使角色的尺寸减半。使用这些值将Scale更改为(X=0.500000,Y=0.500000,Z=0.500000)。

  3. 将奔跑动画应用于预览场景设置选项卡中的这个骨骼网格,并观察半尺寸角色的动画:

以下是预期输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.21:尺寸减半的角色执行奔跑动画

注意

此活动的解决方案可在以下网址找到:packt.live/338jEBx

完成此活动后,您现在已经实际了解了骨骼和骨骼网格的骨骼操作如何影响动画的应用。您还亲身见证了对骨骼的权重缩放对骨骼的影响。

虚幻引擎 4 中的动画

让我们分解动画在虚幻引擎内部的主要方面。关于本节中的主题的更深入信息可以在 Epic Games 的文档中直接找到:docs.unrealengine.com/en-US/Engine/Animation

骨骼

骨骼是虚幻引擎对外部 3D 软件中制作的角色骨骼的表示;我们在活动 10.02骨骼操作和动画中看到了这一点。关于骨骼,我们已经讨论过的内容并不多,但主要的要点是一旦骨骼在引擎中,我们可以查看骨骼层次结构,操作每个单独的骨骼,并添加称为插座的对象。插座允许我们将对象附加到角色的骨骼上,并且我们可以使用这些插座来附加对象,如网格,并且在不破坏骨骼变换的情况下操纵插座的变换。在第一人称射击游戏中,通常会制作武器插座并将其附加到适当的手部。

骨骼网格

骨骼网格是一种特定类型的网格,它结合了 3D 角色模型和构成其骨架的骨骼层次结构。静态网格和骨骼网格的主要区别在于,骨骼网格用于使用动画的对象,而静态网格由于缺乏骨架而无法使用动画。我们将在下一章更深入地研究我们的主角骨骼网格,但我们将在本章后面的Activity 10.03中导入我们的主角骨骼网格,导入更多自定义动画以预览角色奔跑

动画序列

最后,动画序列是一种可以在特定骨骼网格上播放的单独动画;它适用于的网格是在将动画导入到引擎时选择的骨架确定的。我们将在Activity 10.03中导入我们自己的角色骨骼网格和一个单独的动画资产,导入更多自定义动画以预览角色奔跑

我们的动画序列中包含一个时间轴,允许我们逐帧预览动画,并附加了其他控件以暂停、循环、倒带等:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.22:动画序列时间轴和预览窗口

在接下来的练习中,您将导入一个自定义角色和一个动画。自定义角色将包括一个骨骼网格和一个骨架,动画将被导入为动画序列。

练习 10.03:导入和设置角色和动画

对于我们的最后一个练习,我们将导入我们自定义的角色和一个我们将用于SuperSideScroller游戏主角的动画,以及创建必要的角色蓝图和动画蓝图。

注意

本章附带了一个名为Assets的文件夹中的一组文件,我们将导入这些文件到引擎中。这些资产来自 Mixamo:www.mixamo.com/;请随意创建一个账户并查看那里提供的免费 3D 角色和动画内容。

Assets内容可以在我们的 GitHub 上找到:packt.live/2IcXIOo

以下步骤将帮助您完成练习:

  1. 前往虚幻编辑器。

  2. 在“内容浏览器”中,创建一个名为MainCharacter的新文件夹。在这个文件夹中,创建两个名为AnimationMesh的新文件夹。我们的“内容浏览器”选项卡现在应该看起来像下面的图片:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.23:在内容浏览器中的 MainCharacter 目录中添加的文件夹

  1. 接下来,导入我们的角色模型。在我们创建的Mesh文件夹内,右键单击并选择“导入”选项,这将打开文件资源管理器菜单。导航到您保存了本章附带的Assets文件夹的目录,并找到Character Mesh文件夹内的MainCharacter.fbx资产,例如\Assets\Character Mesh\MainCharacter.fbx,然后打开该文件。

  2. 在选择此资产时,将出现 FBX 导入选项窗口。确保在各自的复选框中将“骨骼网格”和“导入网格”的选项设置为“检查”,并将其他选项保持为默认设置。

  3. 最后,我们可以选择“导入”选项,这样我们的 FBX 资产将被导入到引擎中。这将包括在 FBX 中创建的必要材质;一个物理资产,它将自动为我们创建并分配给“骨骼网格”;和“骨架资产”。

注意

忽略导入FBX文件时可能出现的任何警告;它们不重要,不会影响我们未来的项目。

现在我们有了角色,让我们导入一个动画。

  1. MainCharacter文件夹目录中的Animation文件夹内,再次右键单击并选择“导入”选项。

  2. 导航到保存了本章配套Assets文件夹的目录,并在Animations/Idle文件夹中找到Idle.fbx资产,例如\Assets\Animations\Idle\Idle.fbx,然后打开该文件。

选择此资产时,将会出现一个几乎相同的窗口,就像我们导入角色骨骼网格时一样。由于这个资产只是一个动画,而不是骨骼网格/骨架,我们没有之前的选项,但有一个关键的参数需要正确设置:骨架

在我们的FBX导入选项的网格类别下的骨架参数告诉动画应用于哪个骨架。如果不设置这个参数,我们无法导入我们的动画,将动画应用于错误的骨架可能会产生灾难性的结果,或者导致动画根本无法导入。幸运的是,我们的项目很简单,我们已经导入了角色骨骼网格和骨架。

  1. 选择MainCharacter_Skeleton并选择底部的导入选项;将所有其他参数保持为默认设置。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.24:导入 Idle.fbx 动画时的设置

现在我们知道要导入自定义角色网格和动画。了解这两种类型资产的导入过程至关重要,在下一个活动中,您将被挑战导入剩余的动画。让我们继续通过为SuperSideScroller游戏的主角色创建角色蓝图和动画蓝图来进行这个练习。

现在,虽然侧向滚动模板项目确实包括了我们角色的蓝图和其他资产,比如动画蓝图,但为了组织和良好的开发实践,我们将要创建我们自己版本的这些资产。

  1. 内容浏览器MainCharacter目录下创建一个名为蓝图的新文件夹。在该目录中,基于所有类下的SideScrollerCharacter类创建一个新的蓝图。将这个新蓝图命名为BP_SuperSideScroller_MainCharacter外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.25:要用作角色蓝图父类的 SideScrollerCharacter 类

  1. 在我们的蓝图目录中,在内容浏览器的空白区域右键单击,悬停在动画选项上,然后选择动画蓝图外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.26:动画类别下的动画蓝图选项

  1. 选择此选项后,将会出现一个新窗口。这个新窗口要求我们为我们的动画蓝图应用一个父类和一个骨架。在我们的情况下,使用MainCharacter_Skeleton,选择确定,并将动画蓝图资产命名为AnimBP_SuperSideScroller_MainCharacter外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.27:创建动画蓝图时需要的设置

  1. 当我们打开我们的角色蓝图BP_SuperSideScroller_MainCharacter并选择网格组件时,我们会发现一些可以更改的参数:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.28:使用人体模型骨骼网格的 SuperSideScroller 角色蓝图

  1. 网格类别下,我们有更新骨骼网格的选项。找到我们的MainCharacter骨骼网格并将其分配给这个参数:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.29:我们的网格组件需要的设置,以正确使用我们的新骨骼网格和动画蓝图

在我们的角色蓝图中,选择Mesh组件后,我们可以在Mesh类别的正上方找到Animation类别。幸运的是,默认情况下,Animation Mode参数已经设置为Use Animation Blueprint,这是我们需要的设置。

  1. 现在将Anim类参数分配给我们的新动画蓝图,AnimBP_SuperSideScroller_MainCharacter。最后,返回到默认的SideScrollerExampleMap关卡,并用我们的新角色蓝图替换默认角色。

  2. 接下来,请确保我们在Content Browser中选择了BP_SuperSideScroller_MainCharacter,然后右键单击关卡中的默认角色,并选择用我们的新角色替换它:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.30:在内容浏览器中选择角色蓝图后,我们可以简单地右键单击关卡中的默认角色,并用新角色替换它

  1. 在关卡中放置了我们的新角色后,我们现在可以在编辑器中进行游戏并在关卡中移动。结果应该看起来像下面的图片;我们的角色处于默认 T 形姿势并在关卡环境中移动:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.31:您现在有自定义角色在关卡中奔跑

完成我们的最后一个练习后,您现在完全了解了如何导入自定义骨骼网格和动画。此外,您还学会了如何从头开始创建角色蓝图和动画蓝图,以及如何使用这些资产来创建SuperSideScroller角色的基础。

让我们继续进行本章的最后一个活动,在这个活动中,您将被挑战导入角色的剩余动画,并在 Persona 编辑器中预览奔跑动画。

活动 10.03:导入更多自定义动画以预览角色奔跑

这个活动旨在导入剩余的动画,比如玩家角色的奔跑动画,并在角色骨架上预览奔跑动画,以确保它看起来正确。

在活动结束时,所有玩家角色动画将被导入项目中,您将准备好在下一章中使用这些动画来赋予玩家角色生命。

以下步骤将帮助您完成该活动:

  1. 作为提醒,我们需要导入的所有动画资产都存在于\Assets\Animations目录中,无论您将原始zip文件夹保存在何处。导入MainCharacter/Animation文件夹中的所有剩余动画。导入剩余的动画资产将与练习 10.03中的导入和设置角色和动画相同,当您导入Idle动画时。

  2. 导航到MainCharacter骨架,并应用您在上一步中导入的Running动画。

  3. 最后,应用Running动画后,在 Persona 编辑器中预览角色动画。

以下是预期输出:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10.32:带有额外自定义导入资产的角色的预期输出

注意

此活动的解决方案可在以下网址找到:packt.live/338jEBx

完成这个最后的活动后,您现在已经第一手体验了将自定义骨骼和动画资产导入虚幻引擎 4 的过程。无论您导入的资产类型如何,导入过程在游戏行业中很常见,您对此应该感到舒适。

总结

有了玩家角色的骨骼、骨骼网格和动画导入到引擎中,我们可以继续进行下一章,在那里您将准备角色移动和 UpdateAnimation 蓝图,以便角色在关卡中移动时能够进行动画。

通过本章的练习和活动,您了解了骨骼和骨骼如何用于给角色添加动画和操纵。通过第一手经验将动画导入并应用到虚幻引擎 4 中,您现在对动画流程有了深刻的理解,从角色概念到最终导入项目的资产。

此外,您还学习了我们将在下一章中使用的主题,比如用于角色移动动画混合的混合空间。有了创建的SuperSideScroller项目模板和玩家角色准备就绪,在下一章中,让我们开始使用动画蓝图为角色添加动画。

第十章:11.混合空间 1D、键绑定和状态机

概述

本章首先创建所需的混合空间资产,以允许从空闲到行走,最终到奔跑的移动动画混合,根据玩家角色的速度。然后,我们将实现新的键映射,并在 C++中使用这些映射来为玩家角色编写游戏功能,如冲刺。最后,我们将在角色动画蓝图中创建一个新的动画状态机,以便玩家动画可以在移动和跳跃之间平滑过渡。

到本章结束时,当SuperSideScroller玩家角色在环境中移动时,将正确地进行动画处理,并以最适合游戏的方式移动。这意味着玩家将支持空闲、行走和冲刺动画,同时还支持跳跃所需的动画。

介绍

在上一章中,我们对动画和SuperSideScroller项目的游戏设计开发进行了高层次的审视。您只是在项目开发的最初阶段。您还准备了玩家角色的动画蓝图、角色蓝图,并导入了所有必需的骨骼和动画资产。

此时,角色可以在关卡中移动,但却被困在 T 形姿势中,根本没有动画。通过为玩家角色创建一个新的混合空间,可以解决这个问题,这将在本章的第一个练习中完成。完成混合空间后,您将在角色动画蓝图中实现这一点,以便角色在移动时进行动画处理。

在本章中,您将使用许多新的函数、资产类型和变量,以实现玩家角色的期望移动。其中一些包括“动画蓝图”中的“尝试获取所有者”函数、“1D 混合空间资产”类型和项目配置文件中的“输入绑定”。

让我们首先通过学习混合空间,然后创建您需要的混合空间资产,以便在移动时使玩家角色进行动画处理。

混合空间

如其名称所示,混合空间允许您根据一个或多个条件在多个动画之间进行混合。混合空间在不同类型的视频游戏中使用,但通常在玩家可以看到整个角色的游戏中使用。在虚幻引擎 4 提供的第一人称模板项目中,通常不使用混合空间,因为玩家只能看到角色的手臂,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.1:虚幻引擎 4 中第一人称项目模板中默认角色的第一人称视角。

在需要平滑混合角色基于移动的动画的第三人称游戏中,混合空间更常见。一个很好的例子是虚幻引擎 4 提供的第三人称模板项目,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.2:虚幻引擎 4 中第一人称项目模板中默认角色的第三人称视角

混合空间允许玩家角色根据变量或一组变量在动画之间进行混合。例如,在《最后生还者》中的乔尔,他的移动动画是基于他的移动速度的,这个速度是由玩家通过控制器摇杆(或摇杆)提供的。随着速度的增加,他的动画从行走更新到奔跑,然后到冲刺。这就是我们在本章中要实现的目标。

让我们看看 Unreal Engine 提供的混合空间资产,在创建侧向滚动项目模板时,通过打开/Mannequin/Animations/ThirdPerson_IdleRun_2D。这是为侧向滚动人体模型骨骼网格创建的 1D 混合空间资产,以便玩家角色可以根据角色的速度在空闲、行走和奔跑动画之间平滑过渡。

如果你在Persona中检查,在左侧的资产详情面板中,你会看到轴设置类别,其中有水平轴参数,我们可以在我们的动画蓝图中引用的变量。请参考下面的图像查看Persona中的轴设置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.3:这里显示了 1D 混合空间的轴设置

在预览窗口下方,我们还会看到一个小图表,沿着从左到右的线有点;其中一个点将被突出显示为绿色,而其他点为白色。我们可以左键单击并沿着水平轴拖动这个绿色点,以预览基于其值的混合动画。在速度为0时,我们的角色处于空闲状态,当我们沿着轴移动我们的预览时,动画将开始混合行走,然后是奔跑。请参考下面的图像查看单轴图表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.4:这里突出显示了 1D 混合空间的关键帧时间轴

在下一节中,我们将研究 1D 混合空间与普通混合空间的区别。

1D 混合空间与普通混合空间

在继续使用 Unreal Engine 4 中的 1D 混合空间之前,让我们花点时间区分混合空间和 1D 混合空间之间的主要区别。

  • Unreal 中的混合空间资产由两个变量控制,由混合空间图的XY轴表示。

  • 另一方面,1D 混合空间只支持一个轴。

试着把这个想象成一个 2D 图表。你知道每个轴都有自己的方向,你可以更好地想象出为什么以及何时需要使用这个混合空间,而不是只支持单一轴的 1D 混合空间。

比如,假设你想让玩家角色在左右移动的同时也支持前后移动。如果你要在图表上映射这种移动,它会看起来像下面的图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.5:这是一个简单图表上混合空间运动的样子

现在,想象一下玩家角色的移动,记住游戏是一个侧向滚动。角色不会支持左右平移或前后移动。玩家角色只需要在一个方向上进行动画,因为侧向滚动角色默认会朝着移动方向旋转。只需要支持一个方向是你使用 1D 混合空间而不是普通混合空间的原因。

我们需要为我们的主角设置这种类型的混合空间资产,并将其用于相同的目的,即基于移动的动画混合。在下一个练习中,让我们一起使用我们的自定义动画资产创建混合空间资产。

练习 11.01:创建角色移动 1D 混合空间

为了让玩家角色在移动时进行动画,你需要首先创建一个如前所述的混合空间。

在这个练习中,你将创建混合空间资产,添加空闲动画,并更新CharacterMovement组件,以便分配与混合空间相对应的适当行走速度值。

以下步骤将帮助你完成练习:

  1. Content Browser中导航到/MainCharacter/Animation文件夹,其中包含您在上一章中导入的所有新动画。

  2. 现在,在Content Browser的主区域中右键单击,从下拉菜单中悬停在Animation选项上,然后从其附加的下拉菜单中左键单击选择Blend Space 1D

  3. 确保选择MainCharacter_Skeleton,而不是UE4_Mannequin_Skeleton,作为混合空间的骨骼。

注意

如果应用了不正确的骨骼,那么在为需要骨骼的资产(如混合空间或动画蓝图)选择骨骼时,混合空间对于玩家角色和其自定义骨骼网格将无法正常工作。在这里,您正在告诉这个资产它与哪个骨骼兼容。通过这样做,在混合空间的情况下,您可以使用为该骨骼制作的动画,并确保一切与其他一切兼容。

  1. 将此混合空间资产命名为SideScroller_IdleRun_1D

  2. 接下来,打开SideScroller_IdleRun_1D混合空间资产。您可以在预览窗口下方看到单轴图表:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.6:Unreal Engine 4 中用于创建混合空间的编辑工具

在编辑器的左侧,您有包含Axis Settings类别的Asset Details面板。在这里,您将标记轴并提供最小和最大浮点值,这些值稍后将在玩家角色的Animation Blueprint中对您有用。请参考下面的图表,查看为Horizontal Axis设置的默认值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.7:影响混合空间轴的轴设置

  1. 现在,将Horizontal Axis重命名为Speed外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.8:水平轴现在命名为 Speed

  1. 下一步是建立Minimum Axis ValueMaximum Axis Value。您希望最小值默认为0.0f,因为玩家角色在完全不移动时将处于Idle状态。

Maximum Axis Value呢?这个有点棘手,因为您需要记住以下几点:

  • 您将支持角色的冲刺行为,允许玩家在按住左 Shift键盘按钮时移动得更快。释放时,玩家将返回默认行走速度。

  • 行走速度要匹配CharacterMovementComponent的角色Max Walk Speed参数。

在设置Maximum Axis Value之前,您需要将角色的Max Walk Speed设置为适合SuperSideScroller游戏的值。

  1. 为此,导航到/Game/MainCharacter/Blueprints/并打开BP_SuperSideScroller_MainCharacter蓝图:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.9:SuperSideScroller 主角蓝图的目录

  1. 选择Character Movement组件,在Details面板中,在Character Movement: Walking类别下,找到Max Walk Speed参数,并将该值设置为300.0f

Max Walk Speed参数设置后,返回到SideScroller_IdleRun_1D混合空间,并设置Maximum Axis Value参数。如果行走速度为300.0f,最大值应该是多少?请记住,您将支持玩家角色的冲刺,因此这个最大值需要大于行走速度。

  1. Maximum Axis Value参数更新为500.0f

  2. 最后,将Number of Grid Divisions参数设置为5。这样做的原因是,在处理分区时,每个网格点之间的100单位间距使得更容易处理,因为Maximum Axis Value500.0f。在应用动画沿网格时,这对于网格点捕捉非常有用。

  3. 将剩余的属性设置为默认值:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.10:混合空间的最终轴设置

通过这些设置,您告诉混合空间使用0.0f500.0f之间的传入浮点值来在下一步和活动中混合动画。通过将网格分成5个部分,您可以轻松地在轴图表上的正确浮点值处添加所需的动画。

让我们继续创建混合空间,通过将第一个动画添加到轴图表中,即Idle动画。

  1. 在网格的右侧,有Asset Browser选项卡。请注意,资产列表包括您在第十二章 动画混合和蒙太奇中导入的玩家角色的所有动画。这是因为您在创建混合空间时选择了MainCharacter_Skeleton资产。

  2. 接下来,左键单击并将Idle动画拖动到我们的网格位置0.0外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.11:将 Idle 动画拖动到网格位置 0.0

注意,将此动画拖动到网格时,它将捕捉到网格点。一旦动画添加到混合空间中,玩家角色就会从其默认 T 形状改变,并开始播放Idle动画:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.12:将 Idle 动画添加到 1D 混合空间,玩家角色开始动画

完成这个练习后,您现在了解了如何创建 1D 混合空间,更重要的是,您知道了 1D 混合空间和普通混合空间之间的区别。此外,您知道了在玩家角色移动组件和混合空间之间对齐值的重要性,以及为什么需要确保行走速度与混合空间中的值适当地相关。

现在让我们继续进行本章的第一个活动,在这个活动中,您将像添加Idle动画一样,将剩余的WalkingRunning动画应用到混合空间中。

活动 11.01:将 Walking 和 Running 动画添加到混合空间

到目前为止,1D 运动混合空间进展顺利,但您缺少行走和奔跑动画。在本活动中,您将通过将这些动画添加到适合主角的水平轴值的混合空间来完成混合空间。

使用从练习 11.01 创建 CharacterMovement 1D 混合空间中获得的知识,执行以下步骤来完成角色移动混合空间:

  1. 继续进行练习 11.01 创建 CharacterMovement 1D 混合空间,返回Asset Browser

  2. 现在,将Walking动画添加到水平网格位置300.0f

  3. 最后,将Running动画添加到水平网格位置500.0f

注意

请记住,您可以左键单击并沿着网格轴拖动绿色预览网格点,以查看动画根据轴值如何混合在一起,因此请注意角色动画预览窗口,以确保它看起来正确。

预期输出如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.13:混合空间中的 Running 动画

当这个活动完成时,你将拥有一个功能性的混合空间,根据代表玩家角色速度的水平轴的值,将角色的移动动画从Idle混合到Walking再到Running

注意

这个活动的解决方案可以在以下网址找到:packt.live/338jEBx

主角动画蓝图

将动画添加到混合空间后,你应该能够四处走动并看到这些动画在起作用,对吗?嗯,不是的。如果选择在编辑器中播放,你会注意到主角仍然以 T 形姿势移动。原因是因为你还没有告诉动画蓝图使用我们的混合空间资产,这将在本章后面进行。

动画蓝图

在跳入上一章创建的动画蓝图之前,让我们简要讨论一下这种类型的蓝图是什么,以及它的主要功能是什么。动画蓝图是一种蓝图,允许你控制骨骼和骨骼网格的动画,此处指的是上一章导入的玩家角色骨骼和网格。

动画蓝图分为两个主要图表:

  • 事件图

  • 动画图

事件图的工作方式与普通蓝图相同,你可以使用事件、函数和变量来编写游戏逻辑。另一方面,动画图是动画蓝图独有的,这是你在其中使用逻辑来确定骨骼和骨骼网格在任何给定帧的最终姿势。在这里,你可以使用状态机、动画插槽、混合空间和其他与动画相关的节点,然后输出给角色的最终动画。

看一下以下示例(你可以跟着做)。

MainCharacter/Blueprints目录中打开AnimBP_SuperSideScroller_MainCharacter动画蓝图。

默认情况下,AnimGraph应该打开,你可以在其中看到角色预览、我们的Asset Browser选项卡和主图表。就是在这个AnimGraph中,你将实现刚刚创建的混合空间,以便在关卡中移动时玩家角色能够正确地进行动画。

让我们开始下一个练习,我们将在这个练习中做这个,并学习更多关于动画蓝图的知识。

练习 11.02:将混合空间添加到角色动画蓝图

在这个练习中,你将把混合空间添加到动画蓝图,并准备必要的变量来控制这个混合空间,根据玩家角色的移动速度。让我们从将混合空间添加到AnimGraph开始。

以下步骤将帮助你完成这个练习:

  1. 通过在右侧找到Asset Browser左键单击并将SideScroller_IdleRun_1D混合空间资产拖入AnimGraph中,将混合空间添加到AnimGraph

请注意,这个混合空间节点的变量输入标签为Speed,就像混合空间内部的水平轴一样。请参考图 11.14,看看Asset Browser中的混合空间。

注意

如果你给Horizontal Axis取了不同的名字,新名字会显示为混合空间的输入参数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.14:Asset Browser 让你访问与 MainCharacter_Skeleton 相关的所有动画资产

  1. 接下来,将混合空间节点的Output Pose资产连接到Output Pose节点的Result引脚。现在,在预览中的动画姿势显示为角色的Idle动画姿势:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.15:你现在对混合空间有了有限的控制,并可以手动输入值到 Speed 参数中来更新角色的移动动画

  1. 如果你使用PIE,(Idle动画而不是保持 T-Pose:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.16:玩家角色现在在游戏中播放 Idle 动画

现在,你可以使用Speed输入变量来控制我们的混合空间。有了使用混合空间的能力,你需要一种方法来存储角色的移动速度,并将该值传递给混合空间的Speed输入参数。这就是你需要做的:

  1. 导航到我们的动画蓝图的事件图。默认情况下,会有事件蓝图更新动画事件和一个纯Try Get Pawn Owner函数。请参考图 11.17,查看事件图的默认设置。该事件在每帧动画更新时更新,并在尝试获取更多信息之前返回SuperSideScroller玩家角色蓝图类。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.17:动画蓝图包括此事件和函数对,默认情况下在你的事件图中使用

注意

在虚幻引擎 4 中,Pure函数和Impure函数的主要区别在于,Pure函数意味着它包含的逻辑不会修改它所使用的类的变量或成员。在Try Get Pawn Owner的情况下,它只是返回动画蓝图的Pawn所有者的引用。Impure函数没有这个含义,并且可以自由修改任何它想要修改的变量或成员。

  1. Try Get Pawn Owner函数获取Return Value,然后从出现的上下文敏感菜单中搜索转换为SuperSideScrollerCharacter外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.18:上下文敏感菜单可以找到相关的函数或变量,基于这些可以对所检查的对象采取行动

  1. 事件蓝图更新动画的执行输出引脚连接到转换的执行输入引脚:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.19:在事件图中,使用 Try Get Pawn Owner 函数将返回的 Pawn 对象转换为 SuperSideScrollerCharacter 类

你创建的角色蓝图继承自SuperSideScrollerCharacter类。由于这个动画蓝图的拥有者是你的BP_SuperSideScroller_MainCharacter角色蓝图,并且这个蓝图继承自SuperSideScrollerCharacter类,所以转换函数将成功执行。

  1. 接下来,将转换后的返回值存储到自己的变量中;这样,我们在动画蓝图中需要再次使用它时就有一个引用。参考图 11.20,确保将这个新变量命名为MainCharacter

注意

在上下文敏感的下拉菜单中有提升为变量的选项,它允许你将任何有效值类型存储到自己的变量中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.20:只要转换成功,你就会想要跟踪所拥有的角色

  1. 现在,要跟踪角色的速度,使用MainCharacter变量中的Get Velocity函数。Actor类的每个对象都可以访问这个函数,它返回对象移动的大小和方向向量:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.21:GetVelocity 函数可以在 Utilities/Transformation 下找到

  1. 从“获取速度”中,您可以使用VectorLength函数来获取实际速度:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.22:VectorLength 函数返回矢量的大小,但不返回方向

  1. VectorLength函数的Return Value然后可以提升为自己的变量命名为Speed外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.23:每个角色都有 Get Velocity 函数,返回角色移动的大小和方向

在这个练习中,您可以使用GetVelocity函数获得玩家角色的速度。从GetVelocity函数返回的矢量给出了矢量的长度以确定实际速度。通过将这个值存储在Speed变量中,您现在可以在动画蓝图的AnimGraph中引用这个值来更新您的混合空间,在下一个练习中将会这样做。

速度矢量

在进行下一步之前,让我们解释一下当您获取角色的速度并将该矢量的矢量长度提升为Speed变量时,您正在做什么。

什么是速度?速度是一个具有给定GetVelocity函数和返回速度矢量上的VectorLength函数的矢量;您正在获取我们角色的Speed变量的值。这就是为什么您将该值存储在变量中并将其用于控制混合空间的原因,如下图所示,这是矢量的一个示例。其中一个具有正(右)方向,大小为100,另一个具有负(左)方向,大小为35

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.24:显示两个不同的矢量的图

练习 11.03:将混合空间添加到角色动画蓝图

现在您对“矢量”以及如何存储玩家角色的Speed变量有了更好的理解,您可以按照以下步骤将速度应用于本章前面创建的 1D 混合空间。

以下步骤将帮助您完成练习:

  1. 导航到您的AnimBP_SuperSideScroller_MainCharacter动画蓝图中的AnimGraph

  2. 使用Speed变量通过左键单击并将其拖动到AnimGraph中实时更新混合空间,并将变量连接到Blendspace Player函数的输入:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.25:现在您可以在每帧更新动画时使用 Speed 变量来更新混合空间

  1. 接下来,编译动画蓝图。

现在您可以根据玩家角色的速度更新混合空间。当您使用PIE时,您可以看到角色在移动时处于IdleWalking动画中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.26:玩家角色最终能够在关卡中四处走动

最后,主角正在使用基于移动速度的移动动画。在下一个活动中,您将更新角色移动组件,以便可以从混合空间预览角色奔跑动画。

活动 11.02:在游戏中预览奔跑动画

通过更新动画蓝图并获取玩家角色的速度,您现在可以在游戏中预览IdleWalking动画。

在这个活动中,您将更新玩家角色蓝图的CharacterMovement组件,以便您还可以在游戏中预览Running动画。

执行以下步骤来实现这一点:

  1. 导航到并打开BP_SuperSideScroller_MainCharacter玩家角色蓝图。

  2. 访问CharacterMovement组件。

  3. 将“最大行走速度”参数修改为500.0,以便您的角色可以快速移动,从“空闲”到“行走”,最终到“奔跑”时混合其动画。

在本活动结束时,您将允许玩家角色达到一定速度,以便在游戏中预览“奔跑”动画。

预期输出如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.27:玩家角色奔跑

注意

可以在以下网址找到此活动的解决方案:packt.live/338jEBx

现在您已经处理了玩家角色从“空闲”到“行走”,最终到“奔跑”的混合移动,让我们继续下一步,添加功能以允许玩家角色通过奔跑移动得更快。

输入绑定

每个游戏都需要玩家的输入,无论是键盘上的按键,如WASD,用于移动玩家角色,还是控制器上的摇杆;这就是使视频游戏成为互动体验的原因。虚幻引擎 4 允许我们将键盘、鼠标、游戏手柄和其他类型的控件映射到标记的动作或轴上,然后您可以在蓝图或 C++中引用这些动作或轴,以允许角色或游戏功能发生。重要的是要指出,每个独特的动作或轴映射可以有一个或多个按键绑定,并且同一个按键绑定可以用于多个映射。输入绑定保存在名为DefaultInput.ini的初始化文件中,并且可以在项目目录的Config文件夹中找到。

注意

输入绑定可以直接从DefaultInput.ini文件或通过编辑器中的“项目设置”进行编辑;后者在编辑时更容易访问,且更少出错。

让我们为玩家角色的“奔跑”功能添加一个新的输入绑定。

练习 11.04:添加奔跑和投掷输入

随着玩家角色在关卡中移动,您现在将为玩家角色实现一个独特的角色类,该类源自基本的SuperSideScrollerCharacterC++类。这样做的原因是,您可以轻松区分玩家角色和敌人的类,而不仅仅依赖于独特的蓝图类。

在创建独特的 C++角色类时,您将实现“奔跑”行为,以允许玩家角色根据需要“行走”和“奔跑”。

让我们首先通过添加“奔跑”的输入绑定来实现“奔跑”机制:

  1. 在编辑器顶部的工具栏上导航到“编辑”选项,然后从下拉列表中选择“项目设置”。

  2. 在“项目设置”中,导航到左侧“引擎”类别下的“输入”选项。默认情况下,虚幻引擎提供的Side Scroller模板项目为“跳跃”提供了动作映射,键为W上箭头键空格键游戏手柄底部按钮

  3. 通过左键单击“动作映射”旁边的+按钮添加新的“动作映射”。将此映射标记为“奔跑”,并为其控件添加两个键;“左 Shift”和“游戏手柄右肩”。请参考下面的图示以获取更新后的绑定。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.28:应用于按键绑定的跳跃和奔跑动作映射

有了“奔跑”输入绑定后,您需要为基于SuperSideScroller角色类的玩家角色创建一个新的 C++类。

  1. 返回编辑器,导航到“文件”,然后从下拉列表中选择“新建 C++类”选项。

  2. 新的玩家角色类将继承自 SuperSideScrollerCharacter 父类,因为这个基类具有玩家角色所需的大部分功能。选择父类后,左键单击“下一步”。请参考以下图片,看看如何找到 SuperSideScrollerCharacter 类。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.29:选择 SuperSideScrollerCharacter 父类

  1. 将这个新类命名为SuperSideScroller_Player。除非您有必要调整这个新类的文件目录,否则将路径保留为 Unreal Engine 为您提供的默认路径。在命名新类并选择要保存类的目录之后,左键单击“创建类”。

选择“创建类”后,Unreal Engine 将为您生成源文件和头文件,并且 Visual Studio 将自动打开这些文件。您会注意到头文件和源文件几乎是空的。这没关系,因为您是从 SuperSideScrollerCharacter 类继承的,您想要的大部分逻辑都在那个类中完成了。

  1. 在 SuperSideScroller_Player 中,您只会添加您需要的功能。您可以在 SuperSideScroller_Player.h 文件中查看继承正在发生的地方:
class SUPERSIDESCROLLER_API ASuperSideScroller_Player : public ASuperSideScrollerCharacter

这个类声明表示新的 ASuperSideScroller_Player 类继承自 ASuperSideScrollerCharacter 类。

通过完成这个练习,您可以为“冲刺”机制添加必要的“输入绑定”,然后可以在 C++中引用并用于允许玩家进行冲刺。现在您还创建了玩家角色的 C++类,您可以更新代码以添加“冲刺”功能,但首先您需要更新“蓝图”角色和动画蓝图以引用这个新类。让我们在下一个练习中完成这个任务。

当您将蓝图重新设置为新类时会发生什么?每个蓝图都继承自一个父类。在大多数情况下,这是Actor,但在您的角色蓝图的情况下,它的父类是SuperSideScrollerCharacter。从父类继承允许蓝图继承该类的功能和变量,以便逻辑可以在蓝图级别上重用。

例如,当从 SuperSideScrollerCharacter 类继承时,蓝图会继承诸如 CharacterMovement 组件和 Mesh 骨骼网格组件之类的组件,然后可以在蓝图中进行修改。

练习 11.05:重新设置角色蓝图的父类

现在您已经为玩家角色创建了一个新的角色类,您需要更新BP_SuperSideScroller_MainCharacter蓝图,以使用SuperSideScroller_Player类作为其父类。如果不这样做,那么您添加到新类的任何逻辑都不会影响蓝图中创建的角色。

按照以下步骤将蓝图重新设置为新的角色类:

  1. 导航到/Game/MainCharacter/Blueprints/,并打开BP_SuperSideScroller_MainCharacter蓝图。

  2. 在工具栏上选择“文件”选项,然后从下拉菜单中选择“重新设置父蓝图”选项。

  3. 选择“重新设置父蓝图”选项时,Unreal 会要求您为蓝图重新设置父类。搜索SuperSideScroller_Player,然后通过左键单击从下拉菜单中选择该选项。

一旦您为蓝图选择了新的父类,Unreal 将重新加载蓝图并重新编译它,这两个过程都将自动进行。

注意

在将蓝图重新父类化为新的父类时要小心,因为这可能导致编译错误或设置被擦除或恢复为类默认值。虚幻引擎将在将蓝图重新父类化为新类后显示任何可能发生的警告或错误。这些警告和错误通常发生在蓝图逻辑引用不再存在于新父类中的变量或其他类成员的情况下。即使没有编译错误,最好确认在重新父类化之后您对蓝图所做的任何逻辑或设置仍然存在,然后再继续工作。

现在您的角色蓝图已正确重新父类化为新的SuperSideScroller_Player类,您还需要更新AnimBP_SuperSideScroller_MainCharacter动画蓝图,以确保在使用尝试获取所有者函数时转换为正确的类。

  1. 接下来,导航到/MainCharacter/Blueprints/目录,并打开AnimBP_SuperSideScroller_MainCharacter动画蓝图。

  2. 打开事件图。从尝试获取所有者函数的返回值中,搜索转换SuperSideScroller_Player外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.30:与转换为基本 SuperSideScrollerCharacter 类不同,您可以转换为新的 SuperSideScroller_Player 类

  1. 然后,将输出连接为SuperSideScroller_Player转换为MainCharacter变量。这是因为MainCharacter变量是SuperSideScrollerCharacter类型,而新的SuperSideScroller_Player类继承自该类:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.31:您仍然可以使用 MainCharacter 变量,因为 SuperSideScroller_Player 基于 SuperSideScrollerCharacter 进行继承

现在,BP_SuperSideScroller_MainCharacter角色蓝图和AnimBP_SuperSideScroller_MainCharacter动画蓝图都引用了您的新SuperSideScroller_Player类,现在可以安全地进入 C++并编写角色冲刺功能。

练习 11.06:编写角色冲刺功能

在上一次练习中正确实现了新的SuperSideScroller_Player类引用后,现在是时候开始编写功能,允许玩家角色进行冲刺了。

执行以下步骤将冲刺机制添加到角色中:

  1. 首先要处理的是SuperSideScroller_Player类的构造函数。返回 Visual Studio 并打开SuperSideScroller_Player.h头文件。

  2. 您将在本练习的后面使用构造函数来为变量设置初始化值。现在,它将是一个空的构造函数。确保声明是在public访问修饰符标题下进行的,就像下面的代码中所示:

//Constructor
ASuperSideScroller_Player();
  1. 构造函数声明后,在SuperSideScroller_Player.cpp源文件中创建构造函数定义:
ASuperSideScroller_Player::ASuperSideScroller_Player()
{
}

构造函数就位后,现在可以创建SetupPlayerInputComponent函数,以便您可以使用之前创建的按键绑定来调用SuperSideScroller_Player类中的函数。

SetupPlayerInputComponent函数是角色类默认内置的函数,因此您需要将其声明为带有override修饰符的虚拟函数。这告诉虚幻引擎您正在使用此函数,并打算在这个新类中重新定义其功能。确保声明是在Protected访问修饰符标题下进行的。

  1. SetupPlayerInputComponent函数需要将UInputComponent类的对象传递到函数中,如下所示:
protected:
//Override base character class function to setup our player   input component
virtual void SetupPlayerInputComponent(class UInputComponent*   PlayerInputComponent) override;

UInputComponent* PlayerInputComponent变量是从我们的ASuperSideScroller_Player()类继承的UCharacter基类中继承的,因此必须用作SetupPlayerInputComponent()函数的输入参数。使用其他任何名称都将导致编译错误。

  1. 现在,在源文件中创建SetupPlayerInputComponent函数的定义。在函数的主体中,我们将使用Super关键字来调用它:
//Not always necessary, but good practice to call the function in   the base class with Super.
Super::SetupPlayerInputComponent(PlayerInputComponent);

Super关键字使我们能够调用SetupPlayerInputComponent父方法。有了SetupPlayerInputComponent函数准备好了,您需要包含以下头文件,以便在继续进行此练习时不会出现任何编译错误:

  • #include "Components/InputComponent.h"

  • #include "GameFramework/CharacterMovementComponent.h"

您需要包含输入组件的头文件,以便将键映射绑定到接下来将创建的冲刺功能上。Character Movement组件的头文件将对冲刺功能是必需的,因为您将根据玩家是否正在冲刺来更新Max Walk Speed参数。以下是所有需要包含的玩家角色的头文件:

#include "SuperSideScroller_Player.h"
#include "Components/InputComponent"
#include "GameFramework/CharacterMovementComponent.h"

SuperSideScroller_Player类的源文件中包含了必要的头文件后,您现在可以创建用于使玩家角色移动更快的冲刺功能。让我们首先声明所需的变量和函数。

  1. SuperSideScroller_Player类的头文件中的Private访问修饰符下,声明一个名为bIsSprinting的新布尔变量。这个变量将被用作一个保险措施,以确切地知道玩家角色在进行任何移动速度更改之前是否正在冲刺:
private:
//Bool to control if we are sprinting. Failsafe.
bool bIsSprinting;
  1. 接下来,声明两个新函数,Sprint();StopSprinting();。这两个函数不需要任何参数,也不返回任何内容。在Protected访问修饰符下声明这些函数:
//Sprinting
void Sprint();
//StopSprinting
void StopSprinting();

当玩家按住/释放与绑定的Sprint键映射相对应的键时,将调用Sprint();函数,并且当玩家释放与绑定的键相对应的键时,将调用StopSprinting()函数。

  1. Sprint();函数的定义开始。在SuperSideScroller_Player类的源文件中,创建此函数的定义,如下所示:
void ASuperSideScroller_Player::Sprint()
{
}
  1. 在函数内部,您首先要检查bIsSprinting变量的值。如果玩家bIsSprintingFalse,则继续执行函数的其余部分。

  2. If语句内,将bIsSprinting变量设置为True。然后,您可以访问GetCharacterMovement()函数并修改MaxWalkSpeed参数。将MaxWalkSpeed设置为500.0f。请记住,移动混合空间的Maximum Axis Value参数为500.0f。这意味着玩家角色将达到使用Running动画所需的速度:

void ASuperSideScroller_Player::Sprint()
{
    if (!bIsSprinting)
      {
        bIsSprinting = true;
        GetCharacterMovement()->MaxWalkSpeed = 500.0f;
      }
}

StopSprinting()函数几乎与您刚刚编写的Sprint()函数相同,但它的工作方式相反。您首先要检查玩家是否正在冲刺,也就是bIsSprintingTrue。如果是,就继续执行函数的其余部分。

  1. If语句内,将bIsSprinting设置为False。然后,访问GetCharacterMovement()函数来修改MaxWalkSpeed。将MaxWalkSpeed设置回300.0f,这是玩家角色行走的默认速度。这意味着玩家角色只会达到Walking动画所需的速度:
void ASuperSideScroller_Player::StopSprinting()
{
   if (bIsSprinting)
    {
     bIsSprinting = false;
      GetCharacterMovement()->MaxWalkSpeed = 300.0f;
    }
}

现在您已经拥有了需要进行冲刺的功能,是时候将这些功能绑定到您之前创建的动作映射上了。为了做到这一点,在SetupPlayerInputComponent函数中执行以下步骤。

  1. 让我们开始绑定Sprint()函数。在SetupPlayerInputComponent函数内部,使用传递给函数的PlayerInputComponent变量来调用BindAction函数。

我们需要BindAction的参数如下:

  • Project Settings中写入的动作映射的名称,这是您在此练习中之前设置的,这种情况下是Sprint

  • EInputEvent类型的枚举值,您想要用于此绑定;在这种情况下,您将使用IE_Pressed,因为这个绑定将是当按下Sprint键时。

//Bind pressed action Sprint to your Sprint function
PlayerInputComponent->BindAction"Sprint", IE_Pressed, this,   &ASuperSideScroller_Player::Sprint);
  1. 您将对StopSprinting()函数做同样的事情,但这次您需要使用IE_Released枚举值,并引用StopSprinting函数:
//Bind released action Sprint to your StopSprinting function
PlayerInputComponent->BindAction("Sprint", IE_Released, this,   &ASuperSideScroller_Player::StopSprinting);

通过将Action Mappings绑定到奔跑功能,您需要做的最后一件事是设置bIsSprinting变量和Character Movement组件的MaxWalkSpeed参数的默认初始化值。

  1. 在您的SuperSideScroller_Player类的源文件中的constructor函数中,添加bIsSprinting = false行。这个变量被构造为 false,因为玩家角色默认情况下不应该在奔跑。

  2. 最后,通过添加一行GetCharacterMovement()->MaxWalkSpeed = 300.0f,将角色移动组件的MaxWalkSpeed参数设置为300.0f。请查看以下代码:

ASuperSideScroller_Player::ASuperSideScroller_Player()
{
  //Set sprinting to false by default.
   bIsSprinting = false;
  //Set our max Walk Speed to 300.0f
   GetCharacterMovement()->MaxWalkSpeed = 300.0f;
}

通过在构造函数中初始化变量,SuperSideScroller_Player类现在已经完成。返回到虚幻引擎,左键单击工具栏上的Compile按钮。这将重新编译代码并执行编辑器的热重载。

重新编译和热重载编辑器后,您可以在编辑器中进行播放,并看到您努力的成果。基本移动行为与以前相同,但现在如果您按住左 Shift游戏手柄右肩,玩家角色将奔跑并开始播放Running动画。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.32:玩家角色现在可以奔跑

玩家角色能够奔跑后,让我们继续下一个活动,在这个活动中,您将以非常相似的方式实现基本的Throw功能。

活动 11.03:实现投掷输入

这个游戏包含的一个功能是玩家能够向敌人投掷抛射物。在本章中,您不会创建抛射物或实现动画,但您将设置按键绑定和 C++实现,以便在下一章中使用。

在这个活动中,您需要为Throw投射功能设置按键绑定,并在 C++中实现调试日志,当玩家按下与Throw映射的按键时,执行以下操作。

  1. 在输入绑定中的Project Settings中添加一个新的Throw输入。将此绑定命名为ThrowProjectile,并将其绑定到左鼠标按钮游戏手柄右扳机

  2. 在 Visual Studio 中,向SuperSideScroller_Player的头文件中添加一个新的函数。将这个函数命名为ThrowProjectile()。这将是一个没有参数的 void 函数。

  3. SuperSideScroller_Player类的源文件中创建定义。在这个函数的定义中,使用UE_LOG打印一条消息,让您知道函数被成功调用。

注意

您可以在这里了解更多关于UE_LOG的信息:www.ue4community.wiki/Legacy/Logs,_Printing_Messages_To_Yourself_During_Runtime

这个活动结束时的预期结果是,当您使用左鼠标按钮游戏手柄右扳机时,输出日志中将出现一条日志,让您知道ThrowProjectile函数被成功调用。稍后您将使用这个函数来生成您的抛射物。

预期的输出如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.33:预期的输出日志

注意

这个活动的解决方案可以在这里找到:packt.live/338jEBx

完成这个活动后,您现在已经在第十三章 敌人人工智能中创建了玩家投射物的功能。您现在也已经掌握了向游戏添加新的键映射的知识和经验,并且实现了利用这些映射来启用游戏功能的 C++功能。现在,您将继续更新玩家角色移动,以允许玩家跳跃时正确播放跳跃动画。

动画状态机

现在,让我们了解一下在虚幻引擎 4 和动画中状态机的概念。状态机是将动画或一组动画分类到它们自己的状态中的一种方式。状态可以被认为是玩家角色在特定时间内的条件。玩家当前是在走路吗?玩家在跳跃吗?在许多第三人称游戏中,比如最后的生还者,这是将移动、跳跃、蹲下和攀爬动画分离到它们自己的状态中。每个状态在游戏进行时都是可访问的。条件可以包括玩家是否在跳跃、玩家角色的速度以及玩家是否处于蹲下状态。状态机的工作是使用称为转换规则的逻辑决策在各个状态之间进行转换。当您创建多个状态和相互交织的多个转换规则时,状态机开始看起来像一个网络。

请参考以下图片,查看ThirdPerson_AnimBP动画蓝图的状态机外观。

注意

可以在这里找到状态机的一般概述:docs.unrealengine.com/en-US/Engine/Animation/StateMachines/Overview/index.html

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.34:ThirdPerson_AnimBP 的状态机,包含在 SideScroller 项目模板中

对于玩家角色的状态机,这个状态机将处理默认玩家移动和跳跃的状态。目前,玩家角色通过使用由角色速度控制的混合空间来简单地进行动画。在下一个练习中,您将创建一个新的状态机,并将移动混合空间逻辑移动到该状态机内的自己状态。让我们开始创建新的状态机。

练习 11.07:玩家角色移动和跳跃状态机

在这个练习中,您将实现一个新的动画状态机,并将现有的移动混合空间集成到状态机中。此外,您将设置玩家跳跃开始时的状态,以及玩家在跳跃期间的状态。

让我们从添加这个新状态机开始:

  1. 导航到/MainCharacter/Blueprints/目录,并打开AnimBP_SuperSideScroller_MainCharacter动画蓝图。

  2. AnimGraph中,在图表的空白处右键单击,并在上下文敏感搜索中搜索state machine,以找到Add New State Machine选项。将这个新状态机命名为Movement

  3. 现在,我们可以连接新状态机Movement的输出姿势到动画的输出姿势,而不是连接SideScroller_IdleRun混合空间的输出姿势:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.35:新的 Movement 状态机替换了旧的混合空间

将空状态机连接到动画蓝图的Output Pose将导致显示下面的警告。这意味着在该状态机中没有任何操作,结果将无效到Output Pose。不要担心;您将在下一步中解决这个问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.36:空状态机导致编译警告

  1. 双击Movement状态机以打开状态机本身。下面的图像显示了这是什么样子。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.37:这是创建的空状态机

您将首先添加一个新状态,该状态将处理角色之前的操作;空闲行走奔跑

  1. Entry点,左键单击并拖动以打开上下文敏感搜索。您会注意到只有两个选项-添加导管添加状态。现在,您将添加一个新状态并将此状态命名为Movement。请参考以下图像,查看已创建的Movement状态。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.38:在状态机内部,您需要添加一个新状态,该状态将处理您之前创建的移动混合空间

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.39:新的移动状态

  1. 复制并粘贴您在上一步中连接Speed变量到SideScroller_IdleRun混合空间的逻辑到新创建的Movement状态。将其连接到此状态的Output Animation Pose节点的Result引脚:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.40:将混合空间的输出姿势连接到此状态的输出姿势

现在,如果重新编译动画蓝图,您会注意到首先看到的警告现在已经消失。这是因为您添加了一个新状态,该状态将动画输出到Output Animation Pose,而不是拥有一个空状态机。

通过完成这个练习,您已经构建了您的第一个状态机。虽然这是一个非常简单的状态机,但现在您正在告诉角色默认进入并使用Movement状态。如果您现在 PIE,您会看到玩家角色现在像之前制作状态机之前一样移动。这意味着您的状态机正在运行,并且您可以继续下一步,即添加跳跃所需的初始状态。让我们从创建JumpStart状态开始。

转换规则

导管是告诉每个状态可以在何种条件下从一个状态转换到另一个状态的一种方式。在这种情况下,转换规则被创建为MovementJumpStart状态之间的连接。这由连接状态之间的方向箭头指示。工具提示提到术语转换规则,这意味着您需要定义这些状态之间的转换如何发生,使用布尔值来实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.41:需要有一个转换规则从移动到角色跳跃的开始

练习 11.08:向状态机添加状态和转换规则

在从玩家角色的默认移动混合空间过渡到跳跃动画的情况下,您需要知道玩家何时决定跳跃。这可以使用玩家角色的Character Movement组件中的一个有用函数IsFalling来完成。您将希望跟踪玩家当前是否正在下落,以便在跳跃中进行过渡。这样做的最佳方式是将IsFalling函数的结果存储在自己的变量中,就像您在跟踪玩家速度时所做的那样。

以下步骤将帮助您完成此练习:

  1. 回到状态机的概述,左键单击并从Movement状态的边缘拖动以再次打开上下文敏感菜单。

  2. 选择Add State选项并将此状态命名为JumpStart。当您这样做时,虚幻将自动连接这些状态并为您实现一个空的Transition Rule外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.42:虚幻自动为您连接两个状态时创建的 Transition Rule

  1. 返回到动画蓝图中的Event Graph,在那里您使用了事件蓝图更新动画事件来存储玩家角色的Speed外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.43:SuperSideScroller 玩家动画蓝图的 EventGraph

  1. MainCharacter创建一个 getter 变量并访问Character Movement组件。从Character Movement组件,左键单击并拖动以访问上下文敏感菜单。搜索IsFalling外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.44:如何找到 IsFalling 函数

  1. 角色移动组件可以通过IsFalling函数告诉您玩家角色当前是否在空中:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.45:角色移动组件显示玩家角色的状态

  1. IsFalling函数的Return Value布尔值,左键单击并拖动以搜索上下文敏感菜单中的Promote to Variable选项。将此变量命名为bIsInAir。在提升为变量时,返回值输出针应自动连接到新提升的变量的输入针。如果没有,请记得连接它们。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.46:包含 IsFalling 函数值的新变量 bIsInAir

现在你正在存储玩家的状态以及他们是否正在下落,这是MovementJumpStart状态之间的过渡规则的完美候选者。

  1. Movement State机器中,双击Transition Rule进入其图表。您将只找到一个输出节点Result,带有参数Can Enter Transition。在这里,您只需要使用bIsInAir变量并将其连接到该输出。现在,Transition Rule表示如果玩家在空中,则可以发生Movement状态和JumpStart状态之间的过渡。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.47:当在空中时,玩家将过渡到跳跃动画的开始

MovementJumpStart状态之间放置了Transition Rule后,剩下的就是告诉JumpStart状态使用哪个动画。

  1. 从状态机图中,双击JumpStart状态以进入其图表。从“资产浏览器”中,左键单击并将JumpingStart动画拖到图表中:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.48:在左键单击并将其拖入状态之前,确保在资产浏览器中选择了 JumpingStart 动画

  1. Play JumpingStart节点的输出连接到Output Animation Pose节点的Result引脚:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.49:将 JumpingStart 动画连接到 JumpStart 状态的输出动画姿势

在进行下一个状态之前,需要更改JumpingStart动画节点上的设置。

  1. 左键单击Play JumpingStart动画节点,并更新“详细信息”面板以具有以下设置:
  • “循环动画=假”

  • “播放速率=2.0”

请参考以下图表,查看Play JumpingStart动画节点的最终设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.50:由于 JumpStart 动画的缓慢,增加播放速率将导致整体跳跃动画更加流畅

您将将“循环动画”参数设置为False,因为没有理由让这个动画循环;无论如何它都应该只播放一次。这个动画循环的唯一方式是玩家角色在这个状态下被卡住,但由于您将创建的下一个状态,这永远不会发生。将“播放速率”设置为3.0的原因是因为动画本身,JumpingStart,对于您正在制作的游戏来说太长了。动画让角色急剧弯曲膝盖,并在一秒多的时间内向上跳跃。对于JumpStart状态,您希望角色更快地播放这个动画,以使其更流畅,并提供更平滑的过渡到下一个状态;JumpLoop

一旦玩家角色开始JumpStart动画,动画中会有一个时间点,此时玩家在空中,并应该过渡到一个新状态。这个新状态将循环,直到玩家不再在空中,并可以过渡到结束跳跃的最终状态。接下来,让我们创建这个新状态,它将从JumpStart状态过渡。

  1. 从状态机图中,左键单击并从JumpStart状态拖动并选择“添加状态”选项。将此新状态命名为JumpLoop。与以前一样,虚幻将自动为您提供这些状态之间的“转换规则”,您将在下一个练习中添加。最后,重新编译动画蓝图,并忽略编译器结果下可能出现的任何警告。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.51:创建另一个状态,将处理角色在初始跳跃后空中的动画

通过完成这个练习,您已经为JumpStartJumpLoop添加并连接了自己的状态。这些状态通过“转换规则”连接,现在您对状态机中的状态如何通过每个转换规则中建立的规则从一个状态过渡到另一个状态有了更好的理解。

在下一个练习中,您将更深入地了解如何通过函数“剩余时间比例”从JumpStart状态过渡到JumpLoop状态。

练习 11.09:剩余时间比例函数

为了使“跳跃开始”状态顺利过渡到“跳跃循环”状态,您需要花一点时间思考确切地想要这个过渡如何工作。基于“跳跃开始”和“跳跃循环”动画的工作方式,最好在“跳跃开始”动画播放一定时间后过渡到“跳跃循环”动画。这样,“跳跃循环”状态就会在“跳跃开始”动画播放X秒后平稳播放。

执行以下步骤来实现这一点:

  1. 双击“跳跃开始”和“跳跃循环”之间的“过渡规则”以打开其图表。您将应用的“过渡规则”是检查“跳跃开始”动画剩余多少时间。这是因为“跳跃开始”动画还剩下一定比例的时间,您可以安全地假设玩家在空中并准备过渡到“跳跃循环”动画状态。

  2. 要做到这一点,首先确保在“资源浏览器”中选择了“跳跃开始”动画,然后在“过渡规则”的“事件图”中右键单击并找到“时间剩余比率”函数。

让我们花点时间来谈谈“时间剩余比率”函数及其作用。该函数返回一个在0.0f1.0f之间的浮点数,告诉您指定动画剩余多少时间。值0.0f1.0f可以直接转换为百分比值,以便更容易考虑。在“跳跃开始”动画的情况下,您希望知道动画剩余的百分比是否小于 60%,以成功过渡到“跳跃循环”状态。这就是您现在要做的。

  1. 从“时间剩余比率”函数的“返回值”浮点输出参数中,从上下文敏感搜索菜单中搜索“小于比较操作”节点。由于您正在处理一个在0.0f1.0f之间的返回值,为了知道动画剩余的百分比是否小于 60%,您需要将这个返回值与0.6f进行比较。最终结果如下:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.52:在过渡到跳跃循环动画之前,您需要知道跳跃开始动画剩余多少时间

有了这个“过渡规则”,剩下的就是将“跳跃循环”动画添加到“跳跃循环”状态中。

  1. 在“移动”状态机中,双击“跳跃循环”状态以进入其图表。在“资源浏览器”中选择“跳跃循环”动画资产,单击并将其拖放到图表中。将其输出连接到“输出动画姿势”的“结果”输入,如下所示。默认设置的“播放跳跃循环”节点将保持不变。外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.53:跳跃循环动画连接到新状态的输出动画姿势

将“跳跃循环”动画放置在“跳跃循环”状态中后,您现在可以编译动画蓝图并进行 PIE。您会注意到移动和奔跑动画仍然存在,但当您尝试跳跃时会发生什么?玩家角色开始“跳跃开始”状态,并在空中播放“跳跃循环”动画。这很棒,状态机正在工作,但当玩家角色到达地面并不再在空中时会发生什么?玩家角色不会过渡回“移动”状态,这是有道理的,因为您还没有添加“跳跃结束”状态或“跳跃循环”和“跳跃结束”之间的过渡,以及从“跳跃结束”回到“移动”状态。您将在下一个活动中完成这些。请参见下面的示例,其中玩家角色被困在“跳跃循环”状态中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.54:玩家角色现在可以播放跳跃开始动画和跳跃循环动画,但无法过渡回默认移动状态

通过完成这个练习,您已成功使用Time Remaining Ratio函数从JumpStart状态过渡到JumpLoop状态。这个函数允许您知道动画播放到哪个阶段,有了这个信息,状态机就可以过渡到JumpLoop状态。玩家现在可以成功地从默认的Movement状态过渡到JumpStart状态,然后到JumpLoop状态,导致一个有趣的问题。玩家现在被困在JumpLoop状态,因为状态机没有包含回到Movement状态的过渡。让我们在下一个活动中解决这个问题。

活动 11.04:完成移动和跳跃状态机

完成了一半的状态机,现在是时候添加跳跃结束的状态,以及允许您从JumpLoop状态过渡到这个新状态的过渡规则,以及从这个新状态过渡回Movement状态的过渡规则。

完成Movement状态机的以下操作:

  1. 添加一个新的Jump End状态,从JumpLoop过渡。将此状态命名为JumpEnd

  2. JumpEnd动画添加到新的JumpEnd状态。

  3. 根据JumpEnd动画以及我们希望在JumpLoopJumpEndMovement状态之间快速过渡的方式,考虑修改动画的参数,就像你为JumpStart动画所做的那样。循环动画参数需要设置为False播放速率参数需要设置为3.0

  4. JumpLoop状态到JumpEnd状态添加一个过渡规则,基于bIsInAir变量。

  5. 根据JumpEnd动画的Time Remaining Ratio函数,从JumpEnd状态到Movement状态添加一个过渡规则。(查看JumpStartJumpLoop的过渡规则)。

通过本次活动,您将拥有一个完全运作的移动状态机,允许玩家角色空闲、行走、冲刺,以及能够跳跃并在跳跃开始时正确地进行动画,以及在空中和着陆时进行动画。

预期输出如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11.55:玩家角色的空闲、行走、冲刺和跳跃动画

注意

可以在以下链接找到此活动的解决方案:packt.live/338jEBx

通过完成这个活动,您现在已经完成了玩家角色的移动状态机。通过添加剩余的JumpEnd状态和从JumpLoop状态过渡到该状态的过渡规则,以及从JumpEnd状态回到Movement状态的过渡规则,您成功地创建了您的第一个动画状态机。现在,您可以在地图上奔跑并跳上高处的平台,同时正确地进行动画并在移动和跳跃状态之间过渡。

总结

玩家移动混合空间已创建,玩家角色动画蓝图使用状态机从移动到跳跃的过渡,您已准备好进入下一章,在那里您将准备所需的动画插槽、动画剪辑,并更新动画蓝图,以使用角色的上半身进行投掷动画。

通过本章的练习和活动,您学会了如何创建一个 1D 混合空间,允许平滑地混合基于移动的动画,如空闲、行走和奔跑,使用玩家角色的速度来控制动画的混合。

另外,您还学会了如何将新的按键绑定集成到项目设置中,并在 C++中绑定这些按键,以启用角色的游戏机制,如冲刺和投掷。

最后,您学会了如何在角色动画蓝图中实现自己的动画状态机,以便玩家能够在移动动画之间进行过渡,跳跃的各种状态,然后再回到移动状态。有了所有这些逻辑,让我们在下一章继续创建资产和逻辑,允许玩家角色播放投掷动画,并设置敌人的基础类。

第十一章:动画混合和蒙太奇

概述

通过本章结束时,你将能够使用动画蒙太奇工具来创建一个独特的投掷动画,使用你在第十章中导入的投掷动画序列。通过这个蒙太奇,你将创建并使用动画插槽,允许你在玩家角色的动画蓝图中混合动画。你还将了解如何使用混合节点有效地混合角色的移动和投掷动画。

在完成玩家角色动画后,你将为敌人 AI 创建所需的类和资产,并学习更多关于材质和材质实例,这将使这个敌人在游戏中具有独特的视觉颜色,以便可以进行区分。最后,敌人将准备好进入第十三章敌人人工智能,在那里你将开始创建 AI 行为逻辑。

介绍

在上一章中,你通过在混合空间中实现移动动画,并在动画蓝图中使用该混合空间来根据玩家速度驱动动画,使玩家角色栩栩如生。然后,你能够基于玩家输入在 C++中实现功能,允许角色奔跑。最后,你利用动画蓝图内置的动画状态机来驱动角色的移动状态和跳跃状态,以实现在行走和跳跃之间流畅过渡。

随着玩家角色动画蓝图和状态机的工作,现在是时候通过实现角色的“投掷”动画来介绍动画蒙太奇和动画插槽了。在本章中,你将学习更多关于动画混合的知识,看看虚幻引擎如何通过创建动画蒙太奇来处理多个动画的混合,并使用新的保存缓存姿势骨骼层叠混合,以便玩家可以正确地将你在上一章中处理的移动动画与你将在本章实现的新投掷动画进行混合。

让我们首先学习一下什么是动画蒙太奇和动画插槽,以及它们如何用于角色动画。

动画混合、动画插槽和动画蒙太奇

动画混合是在骨骼网格上尽可能无缝地过渡多个动画之间的过程。你已经熟悉了动画混合的技术,因为你在第十一章中为玩家角色创建了一个混合空间资产,其中角色在“空闲”、“行走”和“奔跑”动画之间平滑过渡。现在,你将通过探索和实现新的叠加技术来扩展这些知识,以将角色的移动动画与投掷动画结合起来。通过使用动画插槽,你将把投掷动画发送到一组上半身骨骼和其子骨骼,以便允许移动和投掷动画同时应用而不会对其他动画产生负面影响。但首先,让我们更多地谈谈动画蒙太奇。

动画蒙太奇是一个非常强大的资产,它允许你将多个动画组合在一起,并将这些组合动画分割成所谓的部分。部分可以单独播放,按特定顺序播放,甚至循环播放。

动画蒙太奇也很有用,因为你可以通过蓝图或 C++来控制动画蒙太奇中的动画;这意味着你可以根据正在播放的动画部分或蒙太奇中调用的任何“通知”来调用逻辑、更新变量、复制数据等。在 C++中,有一个UAnimInstance对象,你可以使用它来调用诸如UAnimInstance::Montage_Play之类的函数,这允许你从 C++中访问和播放蒙太奇。

注意

这种方法将在第十四章“生成玩家投射物”中使用,当您开始为游戏添加细节时。关于动画和Notifies在 Unreal Engine 4 中如何通过 C++处理的更多信息可以在docs.unrealengine.com/en-US/API/Runtime/Engine/Animation/AnimNotifies/UAnimNotifyState/index.html找到。

您将在本章的第一个练习中了解更多关于Notifies的内容,并且您将在第十四章“生成玩家投射物”中编写自己的通知状态。

下面的图片显示了动画蒙太奇的Persona编辑器。然而,这将在练习 12.01“设置动画蒙太奇”中进一步拆分:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.1:Persona 编辑器,在编辑动画蒙太奇时打开

就像在动画序列中一样,动画蒙太奇允许在动画的时间轴上触发Notifies,这样可以触发声音、粒子效果和事件。Event Notifies将允许我们从蓝图或 C++中调用逻辑。Epic Games 在他们的文档中提供了一个武器重新加载Animation Montage的示例,该示例分为reload startreload loopreload complete的动画。通过拆分这些动画并应用Notifies来触发soundsevents,开发人员可以完全控制reload loop根据内部变量播放多长时间,以及在动画过程中播放任何额外的声音或效果。

最后,动画蒙太奇支持所谓的Anim Slots。Anim Slots 允许您对动画或一组动画进行分类,稍后可以在 Animation Blueprint 中引用,以允许基于插槽的独特混合行为。这意味着您可以定义一个 Anim Slot,稍后可以在 Animation Blueprint 中使用,以允许使用此插槽的动画以任何您想要的方式在基本移动动画的基础上混合;在我们的情况下,只影响玩家角色的上半身而不影响下半身。

让我们开始为玩家角色的Throw动画创建Animation Montage,这是第一个练习。

练习 12.01:设置动画蒙太奇

玩家角色的最后一件事是设置 Anim Slot,这将单独将此动画分类为上半身动画。您将在 Animation Blueprint 中使用此 Anim Slot,结合混合函数,允许玩家角色投掷投射物,同时在移动和跳跃时正确地对下半身进行动画处理。

通过这个练习结束时,玩家角色将能够仅使用上半身播放Throw动画,而下半身仍将使用您在上一章中定义的movement animation

让我们开始为角色创建Animation Montage,投掷并设置那里的 Anim Slot:

  1. 首先,导航到/MainCharacter/Animation目录,这是所有动画资产的位置。

  2. 现在,在内容浏览器中右键单击,悬停在可用下拉菜单中的Animation选项上。

  3. 然后,左键单击以选择从出现的附加下拉菜单中的Animation Montage选项。

  4. 就像创建其他基于动画的资产一样,比如Blend SpacesAnimation Blueprints,Unreal Engine 会要求您为这个Animation Montage分配一个Skeleton对象。在这种情况下,选择MainCharacter_Skeleton

  5. 将新的Animation Montage命名为AM_Throw。现在,双击打开蒙太奇:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.2:您已成功创建了一个动画蒙太奇资产

打开“动画剪辑”资产时,您会看到类似的编辑器布局,就像打开“动画序列”时一样。有一个“预览”窗口,显示默认的 T 形主角骨架,但一旦您向这个剪辑添加动画,骨架将更新以反映这些变化。

通过完成这个练习,您已成功为“超级横向卷轴”项目创建了一个“动画剪辑”资产。现在是时候了解更多关于动画剪辑以及如何添加您需要的“投掷”动画和动画插槽,以便将“投掷”动画与现有角色移动动画混合。

动画剪辑

看一下下面的图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.3:动画剪辑 Persona 编辑器中的动画预览窗口

在“预览”窗口下方,您有主要剪辑时间轴,以及其他部分;让我们从上到下评估这些部分:

  • “剪辑”部分是可以添加一个或多个动画的动画集合。您还可以右键单击时间轴上的任何点以创建“部分”区域。

  • 部分:如前所述,部分允许您设置单个动画序列的播放顺序以及部分是否应该循环。

为了投掷剪辑的目的,您不需要使用此功能,因为您只会在此剪辑中使用一个动画:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.4:预览窗口和剪辑和部分区域

  • “元素定时”部分为您提供了剪辑的预览以及剪辑各个方面的顺序。通知的播放顺序,“剪辑”部分和其他元素将在这里进行可视化显示,以便您快速预览剪辑的工作方式。

  • “通知”使您能够在动画时间轴上添加点,然后通知其他系统执行操作或从蓝图和 C++中调用逻辑。通知选项,如“播放声音”或“播放粒子效果”,允许您在动画的特定时间播放声音或粒子。一个例子是在武器重新装填的动画中;您可以在动画的时间轴上添加通知,以在重新装填的精确时刻播放重新装填声音。在实现投掷投射物时,您将在项目的后续阶段使用这些“通知”:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.5:元素定时和通知区域

现在您已经熟悉了动画剪辑的界面,您可以按照下一个练习将“投掷”动画添加到剪辑中。

练习 12.02:将投掷动画添加到剪辑中

现在您对动画剪辑是什么以及这些资产如何工作有了更好的理解,是时候将“投掷”动画添加到您在练习 12.01中创建的剪辑中了,设置动画剪辑。尽管您只会向此剪辑添加一个动画,但重要的是要强调您可以向剪辑添加多个独特的动画,然后播放。现在,让我们开始通过添加您在第十章中导入项目的“投掷”动画来开始:

在“资产浏览器”中找到“投掷”动画资产。然后,左键单击并将其拖放到“剪辑”部分下的时间轴上:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.6:带有基于动画的资产的资产浏览器窗口

一旦将动画添加到动画剪辑中,预览窗口中的角色骨架将更新以反映此更改并开始播放动画:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.7:玩家角色开始动画

现在投掷动画已经添加到动画蒙太奇中,您可以继续创建动画槽

动画槽管理器选项卡应该停靠在右侧的资产浏览器选项卡旁边。如果您看不到动画槽管理器选项卡,可以通过导航到顶部动画蒙太奇编辑器窗口的工具栏中的窗口选项卡来访问它。在那里,左键单击选择动画槽管理器选项,窗口将出现。

完成此练习后,您已经将投掷动画添加到了新的动画蒙太奇中,并且可以回放动画,以预览它在Persona编辑器中的外观。

现在,您可以继续学习有关动画槽和动画槽管理器的知识,然后在本章后面的部分中添加自己独特的动画槽,以便用于动画混合。

动画槽管理器

动画槽管理器是您管理动画槽的地方,正如其名称所示。从该选项卡中,您可以通过左键单击添加组选项创建新的,并将其标记为Face,以向其他人说明该组中的槽影响角色的面部。默认情况下,虚幻引擎为您提供了一个名为DefaultGroup和一个名为DefaultSlot动画槽,该槽位于该组中。

让我们创建一个新的动画槽。

练习 12.03:添加新的动画槽

现在您对动画槽和动画槽管理器有了更好的理解,您可以按照以下步骤创建一个名为上半身的新动画槽。创建了这个新槽后,它可以在动画蓝图中使用和引用,以处理动画混合,这将在以后的练习中进行。

让我们通过以下步骤创建动画槽:

  1. 动画槽管理器中,左键单击添加槽选项。

  2. 在添加新槽时,虚幻将要求您给这个动画槽命名。将此槽命名为上半身。动画槽的命名很重要,就像命名其他任何资产和参数一样,因为您稍后将在动画蓝图中引用此槽。

创建了动画槽后,现在可以更新用于投掷蒙太奇的槽。

  1. Montage部分,有一个下拉菜单显示应用的动画槽;默认情况下,它设置为DefaultGroup.DefaultSlot左键单击,然后从下拉菜单中选择DefaultGroup.Upper Body外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.8:新的动画槽将出现在下拉列表中

注意

更改动画槽后,您可能会注意到玩家角色停止动画并返回到 T 形状。不用担心-如果发生这种情况,只需关闭动画蒙太奇,然后重新打开它。重新打开后,角色将再次播放投掷动画。

创建了您的动画槽并放置在投掷蒙太奇中后,现在是时候更新动画蓝图,以便玩家角色意识到这个槽,并根据它正确地进行动画。

  1. 导航到/MainCharacter/Blueprints/目录中的AnimBP_SuperSideScroller_MainCharacter资产。

  2. 通过双击打开此资产并打开动画图

完成此练习后,您已经使用动画槽管理器在动画蒙太奇中创建了您的第一个动画槽。有了这个槽,现在可以在玩家角色动画蓝图中使用和引用它,以处理在上一章中实现的投掷动画和移动动画之间所需的动画混合。在执行此操作之前,您需要了解有关动画蓝图中保存缓存姿势节点的更多信息。

保存缓存姿势

在处理复杂动画和角色时,有时需要在多个地方引用状态机输出的姿势。如果你还没有注意到,你的Movement状态机的输出姿势不能连接到多个其他节点。这就是Save Cached Pose节点派上用场的地方;它允许你缓存或存储一个姿势,然后可以在多个地方引用。你需要使用它来设置上半身动画的新 Anim Slot。

让我们开始吧。

练习 12.04:保存 Movement 状态机的缓存姿势

为了有效地混合使用上一练习中创建的Upper Body Anim Slot和已经存在的玩家角色的移动动画的Throw动画,你需要能够在动画蓝图中引用Movement状态机。为了实现这一点,按照以下步骤在动画蓝图中实现Save Cached Pose节点:

  1. Anim Graph中,右键单击并搜索New Save Cached Pose。将其命名为Movement Cache外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.9:姿势将在每帧评估一次,然后被缓存

  1. 现在,不要直接将你的Movement状态机连接到输出姿势,而是连接到缓存节点:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.10:Movement 状态机正在被缓存

  1. 使用缓存的Movement状态机姿势,现在你只需要引用它。这可以通过搜索“使用缓存的姿势”节点来实现。

注意

所有缓存的姿势都会显示在上下文敏感菜单中。只需确保选择你在步骤 1中给它的名字的缓存姿势。

  1. 有了缓存姿势节点后,将其连接到AnimGraphOutput Pose外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.11:这与将 Movement 状态机直接连接到输出姿势相同

步骤 4之后,你会注意到主角在最后一章之后会正确地进行动画并移动。这证明了Movement状态机的缓存正在工作。下面的图片显示了玩家角色在动画蓝图的预览窗口中回到了Idle动画。

现在,Movement状态机的缓存工作正常,你将使用这个缓存来通过骨骼上的Anim Slot混合动画:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.12:主角正在按预期进行动画

完成这个练习后,你现在可以在动画蓝图中任何你想要的地方引用缓存的Movement状态机姿势。有了这个便利,你现在可以使用缓存的姿势开始在缓存的移动姿势和Upper Body Anim Slot 之间进行混合,使用一个叫做Layered blend per bone的函数。

Layered blend per bone

你将在这里使用的节点是Layered blend per bone。这个节点可以屏蔽角色骨骼上的一组骨骼,使动画忽略这些骨骼。

对于我们的玩家角色和Throw动画,你将屏蔽下半身,以便只有上半身进行动画。目标是能够同时执行投掷和移动动画,并使这些动画混合在一起;否则,当你执行投掷时,移动动画会完全中断。

练习 12.05:使用上半身 Anim Slot 混合动画

“每个骨骼的分层混合”功能允许我们将“投掷”动画与您在上一章中实现的移动动画混合,并控制“投掷”动画对玩家角色骨骼的影响程度。

在这个练习中,您将使用“每个骨骼的分层混合”功能完全屏蔽角色的下半身,当播放“投掷”动画时,以便它不会影响角色下半身的移动动画。

让我们从添加“每个骨骼的分层混合”节点开始,并讨论其输入参数和设置:

  1. 在动画蓝图中,右键单击并在“上下文敏感”搜索中搜索“每个骨骼的分层混合”。

图 12.13显示了“每个骨骼的分层混合”节点及其参数。

  • 第一个参数“基础姿势”是角色的基础姿势;在这种情况下,“移动”状态机的缓存姿势将是基础姿势。

  • 第二个参数是您想要在“基础姿势”上叠加的“混合姿势 0”节点;请记住,选择“添加引脚”将创建额外的“混合姿势”和“混合权重”参数。现在,您只会使用一个“混合姿势”节点。

  • 最后一个参数是“混合权重”,它是“混合姿势”对“基础姿势”的影响程度,范围从0.01.0作为 alpha 值:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.13:每个骨骼的分层混合节点

在连接任何内容到此节点之前,您需要向其属性中添加一个层。

  1. 左键单击选择节点并导航到“详细信息”。您需要左键单击“层设置”旁边的箭头,以找到此设置的第一个索引0左键单击“分支过滤器”旁边的+以创建新的过滤器。

这里再次有两个参数,即以下参数:

  • “骨骼名称”:指定混合将发生的骨骼,并确定被屏蔽的骨骼的子层次结构。在本项目的主角骨架中,将“骨骼名称”设置为“脊柱”。图 12.14显示了“脊柱”骨及其子骨与主角的下半身不相关联。这可以在“骨架”资产MainCharacter_Skeleton中看到:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.14:脊柱骨及其子骨与主角的上半身相关联

  • “混合深度”:骨骼及其子骨受动画影响的深度。值为0将不会影响所选骨骼的根子骨。

  • “网格空间旋转混合”:确定是否在“网格空间”或“本地空间”中混合骨骼旋转。“网格空间”旋转是指骨架网格的边界框作为其基本旋转,而“本地空间”旋转是指所讨论的骨骼名称的局部旋转。在这种情况下,我们希望旋转混合发生在网格空间中,因此我们将将此参数设置为 true。

混合传播到骨骼的所有子骨,以停止在特定骨骼上的混合,将它们添加到数组中,并将它们的混合深度值设为0。最终结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.15:您可以使用一个混合节点设置多个层

  1. 在“每个骨骼的分层混合”节点上设置好参数后,您可以将“移动缓存”缓存姿势连接到分层混合的“基础姿势”节点。确保将“每个骨骼的分层混合”节点的输出连接到动画蓝图的“输出姿势”:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.16:将移动状态机的缓存姿势添加到每个骨骼的分层混合节点

现在是时候使用您之前创建的 Anim Slot,通过Layered blend per bone节点仅过滤使用此插槽的动画了。

  1. AnimGraph右键单击,搜索DefaultSlot左键单击选择Slot节点并导航到Details。在那里,您会找到Slot Name属性。左键单击此下拉菜单,找到并选择DefaultGroup.Upper Body插槽。

在更改Slot Name属性时,Slot节点将更新以表示这个新名称。Slot节点需要一个源姿势,这将再次是对Movement状态机的引用。这意味着您需要为Movement Cache姿势创建另一个Use Cached Pose节点。

  1. 将缓存的姿势连接到Slot节点的源:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.17:通过 Anim Slot 过滤缓存的 Movement 姿势

  1. 现在剩下的就是将Upper Body插槽节点连接到Blend Pose 0输入。然后,将Layered blend per bone的最终姿势连接到Output Pose动画蓝图的结果:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.18:主角动画蓝图的最终设置

在主角动画蓝图中放置了 Anim Slot 和Layered blend per bone节点后,您终于完成了主角的动画部分。

接下来,让我们简要讨论一下“投掷”动画的动画混合的重要性以及“投掷”动画将用于什么,然后再继续练习 12.06,在那里您将在游戏中预览“投掷”动画。

投掷动画

到目前为止,您已经投入了大量的工作,以确保“投掷”动画与之前章节中在动画蓝图中设置的“移动”动画正确融合。这一努力的主要原因是确保角色在执行多个动画时的视觉保真度。在接下来的练习和活动中,您将亲身体会到错误设置动画混合的视觉后果。

回到“投掷”动画,每款现代视频游戏都以某种形式实现动画混合,只要美术指导和游戏机制需要这样的功能。一个极好地运用动画的现代游戏系列的例子是由Naughty Dog开发的Uncharted系列。

如果您对这个系列不熟悉,您可以在这里观看最新版本的完整游戏玩法:www.youtube.com/watch?v=5evF_funE8A

Uncharted系列非常擅长使用成千上万的动画和混合技术,为玩家角色带来令人难以置信的真实感重量感动感,让您在玩游戏时感觉非常良好。虽然Super SideScroller项目不会像这样精致,但您正在学习制作视频游戏中不可思议动画所需的基础知识:

练习 12.06:预览投掷动画

在上一个练习中,您做了很多工作,通过使用Save Cached PoseLayered blend per bone节点,允许玩家角色的Movement动画和Throw动画之间进行动画混合。执行以下步骤,在游戏中预览Throw动画,并看到您劳动的成果:

  1. 导航到/MainCharacter/Blueprints/目录,并打开角色的BP_SuperSideScroller_MainCharacter蓝图。

  2. 如果您还记得,在上一章中,您为投掷创建了名为ThrowProjectileInput Action

  3. 在角色蓝图的“事件图”中,右键单击并在“上下文敏感”下拉搜索中搜索ThrowProjectile。用左键单击选择它,在图表中创建事件节点。

有了这个事件,您需要一个函数,允许您在玩家使用左鼠标按钮投掷时播放“动画蒙太奇”。

  1. 右键单击在“事件图”中搜索Play Montage。确保不要将其与类似的函数Play Anim Montage混淆。

Play Montage函数需要两个重要的输入:

  • Montage to Play

  • “在骨骼网格组件”

让我们首先处理“骨骼网格组件”。

  1. 玩家角色有一个“骨骼网格组件”,可以在标记为“网格”的组件选项卡中找到。左键单击并拖动一个Get引用到这个变量,并将其连接到此函数的In Skeletal Mesh Component输入:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.19:玩家角色的网格连接到 In Skeletal Mesh Component 输入

现在要做的最后一件事是告诉这个函数播放哪个蒙太奇。幸运的是,这个项目中只有一个蒙太奇存在:AM_Throw

  1. Montage to Play输入下的下拉菜单上左键单击,然后左键单击选择AM_Throw

  2. 最后,将ThrowProjectile事件的Pressed执行输出连接到Play Montage函数的执行输入引脚:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.20:当玩家按下 ThrowProjectile 输入动作时,将播放 AM_Throw 蒙太奇

  1. 现在,当您点击左鼠标按钮时,玩家角色将播放投掷“动画蒙太奇”。

现在注意一下,您可以同时行走和奔跑,同时投掷,每个动画都会混合在一起,不会相互干扰:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.21:玩家角色现在可以移动和投掷

不要担心重复使用左鼠标按钮动作播放Throw蒙太奇时可能出现的任何错误;在后面的章节中,当您实现将要投掷的抛射物时,这些问题将得到解决。现在,您只想知道在Anim SlotAnimation Blueprint上所做的工作是否能够实现所需的动画混合结果。

让我们继续通过现在创建 C++类、蓝图和材质来设置敌人,以便在下一章中使用。

超级横向卷轴游戏敌人

当玩家角色在移动和执行Throw动画时正确播放动画时,现在是时候谈论SuperSideScroller游戏将呈现的敌人类型了。我们将有一个简单类型的敌人。

这个敌人将有一个基本的来回移动模式,不支持任何攻击;只有与玩家角色碰撞时才能造成伤害。

在下一个练习中,您将为第一种敌人类型设置基础敌人类的 C++,并配置敌人的蓝图和动画蓝图,为第十三章“敌人人工智能”做准备,在那里您将实现这个敌人的人工智能。为了效率和时间考虑,您将使用 Unreal Engine 4 在SideScroller模板中已经提供的资产用于敌人。这意味着您将使用默认人偶资产的骨架、骨骼网格、动画和动画蓝图。让我们开始创建第一个敌人类。

练习 12.07:创建敌人基础 C++类

本练习的目标是从头开始创建一个新的敌人类,并在 第十三章 敌人人工智能 中准备好使用敌人。首先,按照以下步骤在 C++ 中创建一个新的敌人类:

  1. 在编辑器中,导航到 文件 并选择 新建 C++ 类 来开始创建新的敌人类。

  2. 接下来,请确保在尝试搜索类之前,检查 选择父类 窗口提示的顶部的 显示所有类 复选框。然后,搜索 SuperSideScrollerCharacter左键单击 选择它作为父类。

  3. 最后,您需要给这个类起一个名字并选择一个目录。将这个类命名为 EnemyBase,并不要更改目录路径。准备好后,左键单击 Create Class 按钮,让虚幻引擎为您创建新的类。

当您创建一个新类时,虚幻引擎会自动为您打开 Visual Studio,并准备好 .cpp.h 文件。目前,您不会对代码进行任何更改,因此关闭 Visual Studio。

让我们为敌人资产在内容浏览器中创建文件夹结构。接下来。

  1. 回到虚幻引擎 4 编辑器,导航到内容浏览器,并创建一个名为 Enemy 的新文件夹:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.22:通过右键单击现有文件夹并选择新文件夹来创建新文件夹

  1. Enemy 文件夹中,创建另一个名为 Blueprints 的文件夹,您将在其中创建并保存敌人的蓝图资产。

  2. /Enemy/Blueprints 目录中,右键单击 并选择 蓝图类。从 选择父类 中搜索您刚刚创建的新 C++ 类 EnemyBase,如图所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.23:现在,新的 EnemyBase 类可供您创建蓝图

  1. 将其命名为 BP_Enemy

现在,您已经使用 EnemyBase 类作为父类为第一个敌人创建了 蓝图,是时候处理 动画蓝图 了。您将使用虚幻引擎在 SideScroller 模板项目中提供给您的默认 动画蓝图。按照下一个练习中的步骤创建现有 动画蓝图 的副本并将其移动到 /Enemy/Blueprints 目录。

练习 12.08:创建和应用敌人动画蓝图

在上一个练习中,您创建了使用 EnemyBase 类作为父类的第一个敌人的 蓝图。在这个练习中,您将处理动画蓝图。

以下步骤将帮助您完成此练习:

  1. 导航到 /Mannequin/Animations 目录,并找到 ThirdPerson_AnimBP 资产。

  2. 现在,复制 ThirdPerson_AnimBP 资产。有两种方法可以复制资产:

  • 在内容浏览器中选择所需的资产,然后按 CTRL + W

  • 在内容浏览器中 右键单击 所需的资产,然后从下拉菜单中选择 复制

  1. 现在,左键单击 并拖动此重复的资产到 /Enemy/Blueprints 目录,并在释放 左键单击 鼠标按钮时选择移动选项。

  2. 将此重复的资产命名为 AnimBP_Enemy。最好创建一个资产的副本,以便稍后根据需要进行修改,而不会影响原始资产的功能:

敌人 蓝图动画蓝图 创建完成后,现在是时候更新敌人蓝图,以使用默认的 骨骼网格 人体模型和新的 动画蓝图 副本了。

  1. 导航到 /Enemy/Blueprints 并打开 BP_Enemy

  2. 接下来,导航到 Mesh 组件并选择它以访问其 详细信息 面板。首先,将 SK_Mannequin 分配给 骨骼网格 参数,如图所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.24:您将使用默认的 SK_Mannequin 骨骼网格作为新敌人的角色

  1. 现在,您需要将“AnimBP_Enemy 动画蓝图”应用到Mesh组件上。导航到Mesh组件的“详细信息”面板的“动画”类别,在“动画类”下,分配AnimBP_Enemy外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.25:将新的 AnimBP_Enemy 动画蓝图分配为敌人角色的动画类

  1. 最后,当在“预览”窗口中预览角色时,您会注意到角色网格的位置和旋转不正确。通过将Mesh组件的“变换”属性设置为以下内容来修复这个问题:
  • “位置”:(X=0.000000Y=0.000000Z=-90.000000

  • “旋转”:(Roll=0.000000,Pitch=0,Yaw=-90.000000

  • “缩放”:(X=1.000000one=1.000000Z=1.000000

“变换”设置将如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.26:这些是变换设置,以便您的角色被正确定位和旋转

以下图显示了迄今为止Mesh组件的设置。请确保您的设置与此处显示的相匹配:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.27:敌人角色的 Mesh 组件设置

这里要做的最后一件事是创建人体模型主要材质的“材质实例”,以便这个敌人可以拥有一个独特的颜色,有助于将其与其他敌人类型区分开来。

让我们首先了解更多关于材质和“材质实例”的知识。

材质和材质实例

在继续下一个练习之前,我们需要先简要讨论一下材质和“材质实例”是什么,然后您才能使用这些资产并将它们应用到新的敌人角色上。尽管本书更加关注使用虚幻引擎 4 进行游戏开发的技术方面,但您仍然需要知道材质和“材质实例”是什么以及它们在视频游戏中的使用方式。

注意

有关材质的更多信息,请参考以下 Epic Games 文档:docs.unrealengine.com/en-US/Engine/Rendering/Materials/index.html

材质是一种可以应用于网格的资产类型,然后控制网格在游戏中的外观的资产。 “材质”编辑器让您控制最终视觉结果的许多部分,包括对“纹理”、“自发光”和“高光”等参数的控制。以下图显示了应用了M_UE4Man_Body材质的默认人体模型骨骼网格:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.28:默认的人体模型骨骼网格应用了基本材质

“材质实例”是“材质”的扩展,您无法访问或控制“材质实例”派生的基本“材质”,但您可以控制“材质”创建者向您公开的参数。许多参数可以从“材质实例”内部向您公开以供使用。

Unreal Engine 在“侧向滚动”模板项目中为我们提供了一个Material Instance的示例,名为M_UE4Man_ChestLogo,位于/Mannequin/Character/Materials/目录中。以下图片显示了基于父材质M_UE4Man_BodyMaterial Instance提供的一组暴露参数。要重点关注的最重要的参数是名为BodyColorVector参数。您将在下一个练习中使用这个参数来为敌人角色提供独特的颜色:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.29:M_UE4Man_ChestLogo Material Instance 资产的参数列表

练习 12.09:创建并应用敌人材质实例

现在您已经基本了解了材质和材质实例是什么,是时候从M_UE4ManBody资产创建您自己的Material Instance了。通过这个Material Instance,您将调整BodyColor参数,为敌人角色提供独特的视觉表现。让我们从创建新的Material Instance开始。

以下步骤将帮助您完成此练习:

  1. 导航到/Mannequin/Character/Materials目录,找到默认人体模型角色M_UE4ManBody使用的“材质”。

  2. 可以通过右键单击“材质”资产M_UE4Man_Body,然后左键单击“创建材质实例”选项来创建Material Instance。将此资产命名为MI_Enemy01外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.30:任何材质都可以用来创建材质实例

Enemy文件夹中创建一个名为Materials的新文件夹。左键单击并将Material Instance拖放到/Enemy/Materials目录中,将资产移动到这个新文件夹中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.31:重命名 Material Instance MI_Enemy

  1. 双击Material Instance,在左侧找到Details面板。在那里,您会找到一个名为BodyColorVector Parameter属性。确保复选框被选中以启用此参数,然后将其值更改为红色。现在,Material Instance应该呈现红色,如图所示:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.32:现在,敌人的材质是红色

  1. 保存Material Instance资产,并导航回BP_Enemy01蓝图。选择Mesh组件,并更新“元素 0”材料参数为MI_Enemy外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.33:将新的 Material Instance 资产 MI_Enemy 分配给 Mesh 组件的材料的元素 0

  1. 现在,第一种敌人类型在视觉上已经准备就绪,并且已经准备好适用于下一章的 AI 的适当的Blueprint和动画蓝图资产:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.34:最终敌人角色设置

完成此练习后,您现在已经创建了一个Material Instance并将其应用于敌人角色,使其具有独特的视觉表现。

让我们通过进行一个简短的活动来结束本章,这将帮助您更好地理解使用Layered blend per bone节点来混合动画,这是在之前的练习中使用的。

活动 12.01:更新混合权重

在“练习 12.06”结束时,“预览投掷动画”,您能够混合移动动画和“投掷”动画,以便它们可以同时播放而不会对彼此产生负面影响。结果是玩家角色在行走或奔跑时能够正确执行动画,同时在上半身执行“投掷”动画。

在这个活动中,您将尝试使用Layered blend per bone节点的混合偏差值和参数,以更好地理解动画混合的工作原理。

以下步骤将帮助您完成此活动:

  1. 更新Layered blend per bone节点的Blend Weights输入参数,以确保Throw动画的附加姿势与基础移动姿势完全不混合。尝试在这里使用值,如0.0f0.5f,以比较动画中的差异。

注意

确保在完成后将此值返回为1.0f,以免影响您在上一个练习中设置的混合。

  1. 更新Layered blend per bone节点的设置,以更改受混合影响的骨骼,以便整个角色的身体都受到混合的影响。从MainCharacter_Skeleton资产的骨骼层次结构中的根骨骼开始是个好主意。

  2. 保持上一步的设置不变,向分支过滤器添加一个新的数组元素,并在这个新的数组元素中,添加骨骼名称和混合深度值“-1.0f”,这样只有角色的左腿在混合 Throw 动画时才能继续正确地播放移动动画。

注意

完成此活动后,请确保将Layered blend per bone节点的设置返回到第一个练习结束时设置的值,以确保角色动画不会丢失任何进展。

预期输出如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.35:显示整个角色身体受影响的输出

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.36:当混合 Throw 动画时,左腿继续正确地播放移动动画

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12.37:角色的右腿在移动时播放 Throw 动画的结尾

注意

此活动的解决方案可在以下链接找到:packt.live/338jEBx

在结束本活动之前,请将Layered blend per bone设置返回到练习 12.05“使用上半身动画插槽混合动画”的最后设置的值。如果您不将这些值恢复到原始设置,那么下一章节中即将进行的练习和活动中的动画结果将不同。您可以手动设置回原始值,或者参考以下链接中具有这些设置的文件:packt.live/2GKGMxM

完成此活动后,您现在对动画混合的工作原理和混合权重如何影响Layered blend per bone节点上的附加姿势对基础姿势的影响有了更深入的理解。

注意

在这个项目中,您还没有使用许多动画混合技术,强烈建议您研究这些技术,首先查看docs.unrealengine.com/en-US/Engine/Animation/AnimationBlending/index.html上的文档。

总结

通过使用 C++类、蓝图和材质设置敌人,您已经准备好进入下一章节,在那里您将利用虚幻引擎 4 中的行为树等系统为这个敌人创建 AI。

从本章的练习和活动中,您学会了如何创建一个“动画蒙太奇”,允许播放动画。您还学会了如何在这个蒙太奇中设置一个动画插槽,以便为玩家角色的上半身进行分类。

接下来,您将学习如何使用“使用缓存姿势”节点来缓存状态机的输出姿势,以便在更复杂的动画蓝图中可以引用这个姿势的多个实例。然后,通过学习“每骨层混合”功能,您可以使用动画插槽将基本移动姿势与“投掷”动画的附加层进行混合。

最后,您将通过创建 C++类、蓝图和其他资产来组建敌人的基础,以便为下一章做好准备。敌人准备就绪后,让我们继续创建敌人的人工智能,以便它可以与玩家进行互动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值