环境危险因素可以在塑造Gameplay方面发挥着重要作用。 通过使用危险因素和陷阱,你可以为玩家增添行为的后果,并随着他们在解谜或关卡中取得进展而提升相应的难度和紧张感。
在教程系列的这个部分中,你将创建可以对玩家造成伤害的尖刺陷阱和火焰陷阱。 然后,你需要将火焰陷阱和开关的Gameplay对象连接起来,创建新的Gameplay机制和谜题。
现在玩家会承受伤害并失去所有生命值,你还需要设置一个结束并重新启动游戏的失败条件,让玩家有重试的机会。
开始之前
请确保你已掌握设计解谜冒险游戏前几节讲述的以下内容:
蓝图基础知识,如变量、函数、事件图表和添加节点。
使用蓝图接口事件来切换另一个Gameplay对象。
你需要准备好在创建钥匙和谜题:开关和立方体中创建的下列资产:
M_BasicColor材质和M_BasicColor_Red材质实例BPI_Interaction蓝图接口BP_Switch蓝图类
构建一组相关蓝图类
在本教程系列中,你已经见过使用父节点-子节点关系和继承的虚幻引擎资产。 继承(Inheritance)意味着创建一个新的子节点,该子节点复用并扩展现有父节点的功能。 子类可以在这些功能的基础上进行扩展,而无需更改父节点。 继承可以在许多资产中复用功能,而不是手动将它们添加到每个新资产,从而节省你的时间。
你的材质实例资源会从其父材质继承功能。 在之前的许多蓝图中,你已经创建了从父节点继承变换数据的组件。
游戏中通常会设置不同类型的危险因素,但它们的核心功能基本都是相同的。 父节点陷阱蓝图可以定义这些共享的功能,而每个子节点陷阱蓝图都可以扩展这些功能,添加不同的视觉效果和行为。
你的基础(父节点)陷阱需要检测玩家重叠,并使用伤害游戏机制逐渐减少玩家的生命值。 然后你将创建(或子类化)子陷阱,以扩展基本陷阱的功能并添加额外的视觉效果或行为。 尖刺陷阱会在外观上添加额外的静态网格体,而火焰陷阱会添加火焰效果和行为,使其能够打开和关闭。
你的关卡仍处于布局阶段,所以要创建每个陷阱的简化版本,以便为未来的视觉效果设计提供参考。
创建基础陷阱蓝图
首先我们要创建基础陷阱蓝图类,作为特殊陷阱的父节点和基础。
要创建定义通用陷阱功能的蓝图,请按照下列步骤操作:
在内容浏览器中,找到Content > AdventureGame > Designer > Blueprints文件夹,然后创建一个名为
Traps的新文件夹。在Trap文件夹中,右键点击或点击添加(Add),然后创建新的蓝图类。
在
Pick Parent Class窗口中,单击Actor。将此类命名为
BP_TrapBase并将其打开。
添加组件
对于基础陷阱,你可以创建粗模的静态网格体以显示陷阱的边界。 所有陷阱还需要碰撞体积,以便在玩家踩踏它们时发现。
要创建基础陷阱的物理组件,请执行以下步骤:
在组件(Components)选项卡中,点击添加(Add),然后搜索并添加立方体静态网格体形状。
将网格体组件命名为
TrapBase。在细节面板的变换(Transform)下,将立方体的缩放(Scale)更改为
2,2,0.1,以创建扁平的正方形底面。在组件(Components)选项卡中,选择TrapBase,点击添加(Add),然后搜索并选择盒体碰撞组件。
将碰撞组件命名为
TrapTrigger。 这是玩家站在陷阱上时用于检测的碰撞体积。就像
BP_Switch一样,你要把碰撞组件附加到网格体,如果你想更改陷阱的大小,触发器区域也会自动调整。在细节面板的变换(Transform)下,更改以下属性,在基础网格体上方创建一个大的碰撞盒体:
将位置(Location)设置为
0、0、400。将缩放设置为
1.5,1.5,12。
添加变量后的面板
所有陷阱还需要可编辑的属性,以便进行自定义:
危险是激活还是不激活。
陷阱对玩家造成的伤害。
伤害间隔,或两次命中之间的时间。
并且陷阱需要知道是谁与它碰撞。
要将常用属性添加到基础陷阱,请执行以下步骤:
在我的蓝图(My Blueprint)选项卡中,创建以下变量:
变量名称
类型
类别
默认值
Active
布尔(Boolean)
设置
True
BaseDamage
浮点(Float)
设置
5.0
DamageInterval
浮点(Float)
设置
1.0
创建变量后,编译蓝图以添加默认值。
点击每个变量的眼睛图标,打开眼睛,使所有三个变量都可编辑并公开。
添加一个名为
OtherActor的变量,并将类型更改为Actor (Object Reference)(Actor(对象引用))。
创建应用伤害的函数
现在你的陷阱有了基本属性,可以开始创建陷阱的行为了。 当玩家与碰撞体积重叠时,所有陷阱都会定期降低玩家的生命值(HP)。
虚幻引擎有许多内置的常见游戏机制解决方案,包括施加和接收伤害。
对于陷阱,你将使用内置的Apply Damage函数节点。 我们要整理一下伤害处理的逻辑,创建自己的函数,在陷阱处于激活状态时,对接触陷阱的所有角色调用Apply Damage。
请按照以下步骤,创建一个对玩家造成陷阱伤害的函数:
在函数选项中,点击添加。 将此函数命名为
fnApplyDamageToTargets并打开其图表。你只想在陷阱打开并激活时施加伤害,因此要添加一个Branch节点,其中Condition是对Active 变量的引用(Get)。
之后的教程中,你将添加一些NPC敌人,以便同时有多个Actor位于陷阱上。 因此,当陷阱处于激活状态时,循环遍历所有接触陷阱的Actor的数组:
将Branch节点的True引脚连接到For Each Loop节点。
对于循环的数组输入,你需要创建所有重叠Actor的数组。 虚幻引擎会自动为你执行此操作,即添加Get Overlapping Actors (TrapTrigger)节点。 该节点还有对目标TrapTrigger的引用。
在Get Overlapping Actors节点中,将Class Filter更改为Character,以便可以将玩家和NPC角色添加到数组。
对于每个数组元素或循环的每个迭代,将BaseDamage变量中设置的伤害量应用于该数组元素中的Actor。 为此,将Apply Damage节点连接到Loop Body。
Apply Damage函数来自虚幻引擎Game Statics库。 右上角的图标表示该函数可以在联网游戏中使用,并且可以在服务器上运行。
设置Apply Damage节点:
对于Damaged Actor引脚,要连接循环的Array Element。
对于Base Damage引脚,将引用连接到BaseDamage变量。
6. 保存并编译蓝图。
完整的fnApplyDamageToTarget 函数应如下所示:
如果你要将此代码片段复制并粘贴到项目中的相应图表中,请将函数条目节点连接到Branch节点。
创建随时间施加伤害的定时器
接下来,你需要让陷阱定期调用apply-damage函数。 因此要使用虚幻引擎的一种定时器函数来创建定时器。
在此蓝图中,你将使用Set Timer by Function Name
此节点会创建定时器并将函数绑定到该定时器,以便在定时器到期时,节点调用该函数,执行该函数中的所有操作。
要在游戏开始时设置定时器,请执行以下步骤:
找到
BP_TrapBase的事件图表选项卡。 删除Event ActorBeginOverlap和Event Tick节点。在陷阱执行任何操作之前,你需要检查它是否已激活。 从Event BeginPlay节点添加一个Branch节点,其中Condition是对Active变量的引用。
从Branch节点的True引脚,创建Set Timer by Function Name节点。
设置定时器节点:
对于Time引脚,连接对DamageInterval变量的引用。
点击Function Name旁边的文本框,并输入
fnApplyDamageToTarget。确保你正确拼写了函数名称,否则逻辑将无法正确执行。
启用Looping(循环)。
Set Timer节点会输出一个名为"Timer Handle的返回值,其作用类似于定时器的跟踪编号或控制器。 要停止、暂停或恢复定时器,就会引用此定时器句柄,因此要把它保存在新变量中:
在我的蓝图面板中,创建一个名为
TimerHandler的新变量。 将其类型更改为计时器句柄(Timer Handle)。添加Set Timer Handler节点,并将其连接到Set Timer by Event的返回值和执行引脚。
在虚幻引擎创建定时器时,它会立即开始运行,因此你需要暂停定时器,直到有角色踩到陷阱。 连接Pause Timer by Handle节点并为其提供TimerHandler。
保存并编译蓝图。
开始和停止伤害
你已经创建并暂停了伤害定时器,它已准备就绪,蓄势待发。 现在我们要使伤害在角色踏上陷阱的碰撞体积时恢复,并在角色停止与体积重叠时暂停。
请按照以下步骤,添加用于启动伤害的逻辑:
在组件(Components)面板中,右键点击TrapTrigger组件,转到添加事件(Add Event),然后选择添加OnComponentBeginOverlap(Add OnComponentBeginOverlap)。
事件之后,连接Set Other Actor节点,将重叠的Actor保存在变量中。
连接事件和Set节点的Other Actor引脚。
连接fnApplyDamageToTarget节点,使角色在接触陷阱时立即受到伤害。
连接Unpause Timer by Handle节点以恢复定时器和伤害间隔。 对于Handle input,将引用连接到TimerHandler变量。
请按照以下步骤,添加用于停止持续伤害的逻辑:
右键点击TrapTrigger组件,找到添加事件(Add Event)> 在组件结束重叠时(On Component End Overlap)。
事件结束后,连接Pause Timer by Handle节点,再次为其提供TimerHandler的引用。
保存并编译蓝图。
陷阱现在会创建、启动和暂停伤害定时器。
完成后的BP_TrapBase事件图表应如下所示:
有关定时器和定时器管理的更多信息,请参阅Gameplay定时器。
测试基础陷阱
要测试陷阱,请添加一条打印字符串(Print String)消息,该消息在陷阱施加伤害时在屏幕上进行报告。
要在屏幕上打印消息,显示陷阱正在按预期工作,请执行以下步骤:
在
BP_TrapBase中,转到fnApplyDamageToTarget选项卡。在函数的图表中,在Apply Damage节点后面连接一个Print String节点。
将In String更改为
Player hit!点击Print String节点底部的箭头以显示更多选项,并将Duration更改为
5。 这样就可以更方便地查看随时间推移而造成的损害。编译并保存此蓝图。 在内容浏览器中,将
BP_TrapBase的实例拖动到你的关卡中。运行关卡并踩踏陷阱。 新的"Player hit!"消息应该每秒显示一次。
创建尖刺陷阱子类
完成父类以后就可以开始创建子类了!
首先,你要创建一个尖刺陷阱,它会修改基础陷阱的外观,添加一些形状语言。 普通的扁平陷阱看起来并不危险,但玩家看到将带有尖刺的东西就知道它可能会造成伤害。
要创建尖刺陷阱,请按照以下步骤操作:
在内容浏览器的Traps文件夹中,右键点击
BP_TrapBase,然后选择Create Child Blueprint Class。将蓝图类命名为
BP_TrapSpikes并将其打开。在组件(Components)选项卡中,选中DefaultSceneRoot,点击添加(Add),然后搜索并选择椎体(Cone)。
你可以调整椎体的大小和位置以适应四行排列,每行四个椎体(或总共16个椎体)。
在锥体的细节面板的变换选项中,更改以下属性:
将位置更改为
-75、-75、25。将缩放更改为
0.5、0.5、0.4。
现在在基础网格体的边角处有一个更小的尖刺。
要获得一定的视觉对比度,在材质(Materials)选项中,使用下拉菜单将锥体的材质更改为
M_BasicColor_Red。选择并复制(Ctrl+D)椎体3次,将每个椎体平移50个单位,以便它们在基础网格体的一侧排成一行。
按住Ctrl键选择所有四个锥体并复制它们。 在组件(Components)面板中,选择四个新椎体(它们将具有最大的数字后缀),并将其移动50个单位。 重复此操作两次,以创建4x4的锥体网格。
尖刺中的斜面和角度可能会使玩家很难离开陷阱。 要防止玩家卡在在尖刺之间,请在尖刺顶部添加一个不可见的地板:
在组件(Components)选项卡中,复制TrapBase网格体并将其命名为
InvisFloor。将地板上移,这样在地板上方只能看到尖刺的尖端。
在细节面板的碰撞(Collision)选项中,确保碰撞预设(Collision Presets)设置为BlockAllDynamic。 这会阻止所有Actor穿过模型。
在渲染(Rendering)分段中,禁用可见(Visible)。 这会在视口中和Gameplay期间隐藏模型。
在组件(Components)选项卡中,选择TrapBase网格体。 在细节面板的渲染(Rendering)选项中,启用在游戏中隐藏(Hidden in Game)。 这会使网格体在视口中可见,但在Gameplay期间将其隐藏,因此你只会看到尖刺。
保存并编译蓝图。
尖刺陷阱子类具有基础陷阱的所有行为,因此它被触发的时候还会打印"Player hit!"。 将BP_TrapSpikes的实例拖到你的关卡中并进行测试!
创建火焰陷阱子类
接下来,我们要创建一种陷阱来扩展基本陷阱的行为。 火焰陷阱会增加危险性,但玩家可以使用开关将其关闭,这也是一种可以转化为新谜题的Gameplay机制。
在谜题:开关和立方体中,你创建了BPI_Interaction蓝图接口,开关可以使用它来打开和关闭其他Gameplay对象。 你还可以在陷阱蓝图中使用此接口,以便开关可以在Gameplay期间更改陷阱的Active变量。
首先,你需要一个新材质,以便在陷阱停用时使用。
要为火焰陷阱创建黑色材质,请按照以下步骤操作:
在内容浏览器中,转到 AdventureGame > Designer > Materials文件夹。
右键点击
M_BasicColor并选择创建材质实例(Create Material Instance)。将材质实例命名为
M_BasicColor_Black并将其打开。展开全局向量参数值(Global Vector Parameter Values),启用颜色(Color),然后点击色条将其更改为深灰色(十六进制值 sRGB =
3D3B3BFF)。 这在游戏中会比纯黑色的观感更好。保存并关闭材质实例。
要对火焰陷阱进行子类化,请执行以下步骤:
在内容浏览器中,右键点击
BP_TrapBase并选择创建子蓝图类(Create Child Blueprint Class)。将蓝图命名为
BP_TrapFire并将其打开。更改基础网格体的颜色,使其代表火焰陷阱。 选择TrapBase组件,在细节面板的材质选项中,将材质更改为
M_BasicColor_Red。在视口上方,点击类设置(Class Settings)。
在细节面板的接口分段中,在实现的接口旁边,点击添加,然后搜索并选择
BPI_Interaction。在我的蓝图(My Blueprint)面板中,fnBPISwitchOff和fnBPISwitchOn事件函数会出现在接口(Interfaces)分段中。
就像
BP_Switch一样,为火焰陷阱设置可自定义的材质:在我的蓝图(My Blueprint)面板的变量(Variables)分段中,创建名为
OffMaterial和OnMaterial的两个变量。将其类型更改为材质接口(对象引用)[Material Interface (Object Reference)]。
点击其眼睛图标,将其设为公开可编辑。
将类别更改为Setup。
编译并设置以下默认值:
OffMaterial:
M_BaseColor_BlackOnMaterial:
M_BaseColor_Red
保存并编译该蓝图,这样可以在陷阱事件图表中使用接口事件。
扩展陷阱的行为
就像你在谜题:移动平台中创建移动平台一样,你需要设置陷阱的事件图表,以便在开关调用fnBPISwitchOn和fnBPISwitchOff时执行以下操作:
激活或停用陷阱。
更改陷阱的材质。
对于移动平台,你需要让平台在玩家激活开关时开始移动。 对于陷阱,你需要相反的东西 — 关卡开始时陷阱处于激活状态,并且应该在玩家激活开关时关闭。
要添加在玩家按下开关时停用火焰陷阱的逻辑,请执行以下步骤:
转到火焰陷阱的事件图表(EventGraph)选项卡。 在我的蓝图(My Blueprint)面板的接口(Interfaces)列表中,双击fnBPIButtonOn以将事件节点添加到图表。
BP_TrapBase变量不会出现在我的蓝图(My Blueprint)面板中,但你可以通过节点操作列表访问它们。 从Event fnBPISwitchOn节点的执行引脚拖出引脚,搜索active variable,然后选择Set Active。 保持Active禁用状态。在Set 节点后,连接Set Material (TrapBase)节点(在操作列表的渲染(Rendering)> 材质(Material)分段中)。
在Set Material节点中,将对OffMaterial变量的引用连接到材质引脚。
要添加在开关停用时激活火焰陷阱的逻辑,请执行以下步骤:
在接口(Interfaces)分段中,双击Event fnBPISwitchOff以添加该节点。
事件之后,连接Set Active变量节点,但这次启用Active。
在Set节点之后,连接Set Material (TrapBase)节点并连接对OnMaterial的引用。
保存并编译蓝图。
完成后,你的完整火焰陷阱事件图表应如下图所示:
将BP_TrapFire的实例添加到关卡中试一试!
使用玩家生命值更新HUD
是时候将这些Print String节点替换为一些针对玩家的真实反馈了。 你需要更改HUD,以便实时报告玩家的生命值。
将HP变量添加到HUD
要将动态玩家生命值添加到HUD,请执行以下步骤:
在内容浏览器中,打开你的
WBP_PlayerHUD控件蓝图。 确保你在设计器视图中。在层级(Hierarchy)中,点击txtHP控件。 在细节面板中,启用是变量并从文本(Text)属性中删除100。
转到图表视图并设置一个新函数来设置txtHP的值:
在函数(Functions)分段中,添加名为fnSetHP的新函数。
选择函数后,在细节面板中,点击输入(Inputs)旁边的+。
将输入参数命名
NewHP,并将其类型更改为浮点数。稍后,你将更改玩家角色,使其在受到伤害时调用此函数。
在fnSetHP函数的图表中,在函数入口节点后,连接SetText (Text)节点。
如果你在节点操作列表中找不到节点,请禁用上下文关联(Context Sensitive)。
设置SetText (Text)节点:
对于Target,将引用连接到txtHP变量。 这是显示玩家生命值的文本控件。
对于In Text,连接函数条目节点的New HP输入引脚。 虚幻引擎会自动添加To Text (Float)节点来转换数值。
保存并编译控件蓝图。
完整的fnSetHP 函数图表如下所示:
如果是将此蓝图代码段复制到图表中,则需要将函数入口节点连接到SetText和To Text节点。
显示玩家的初始生命值
在显示任何可用的HUD变量之前设置它们。 在本例中,你知道玩家的初始生命值,因此可以在游戏开始时显示该信息。
要更新玩家角色蓝图以在HUD上显示其HP,请执行以下步骤:
在内容浏览器中,打开
BP_AdventureCharacter蓝图。 在事件图表中,找到Event Possessed逻辑。在我的蓝图(My Blueprint)面板中,展开图表(Graphs) > 事件图表(EventGraph)并双击图表中的Event Possessed以选中它。
在Set节点和Add to Viewport节点之间,连接一个fnSetHP节点:
对于目标,使用Set节点的输出引脚使HUD成为目标。
将New HP的引用连接到玩家的Health变量。
确保Add to Viewport节点的Target引脚也连接到HUD变量节点。
在我的蓝图(My Blueprint) 面板中,点击Health变量。 在细节面板中,更改(或保留)默认值。 本教程使用的初始生命值为100。
保存和编译。
玩家的新Event Possessed逻辑应如下所示:
如果要将此逻辑复制到你的项目中,请首先删除现有的Event Possessed逻辑组。
现在HUD会在游戏开始时显示玩家的生命值。 最后需要的逻辑是在玩家受到伤害时更新HUD。 为此,我们要修改角色的现有伤害处理逻辑,以使用你的HUD。
在受到伤害后更新玩家的生命值
请按照以下步骤,处理对玩家造成的伤害:
在
BP_AdventureCharacter事件图表的左下角,找到以Event AnyDamage节点开头的标记为Damage and death handling的逻辑分段。 我们要修改此分段,改为执行你自己的逻辑。删除Branch节点之后的所有节点。 保留Branch节点。
此逻辑分段使用运算符节点(operator node)来执行计算。 当角色受到伤害时,Event AnyDamage节点会触发,传递有关造成的伤害、伤害类型以及发起伤害的控制器和Actor的信息。 接下来,从角色的Health变量中减去伤害值。 减去生命值后,Branch节点会检查玩家的生命值是否已达到0。
现在,你需要构建在玩家生命值大于0时更新HUD的逻辑。 因此,从False引脚连接FnSetHP 节点,将新的生命值发送到HUD。
设置fnSetHP节点:
对于Target,将引用连接到角色的HUD变量。
对于New HP输入,连接对Health变量的引用。
保存并编译蓝图。
现在HUD会显示玩家的当前生命值,并在玩家受到伤害时更新该数值。
返回到BP_TrapBase蓝图,删除添加到基础陷阱事件图表中的所有Print String节点。
再次运行游戏并测试一下!
创建失败和重生条件
当玩家的生命值耗尽并被淘汰时,就需要停止游戏,并让玩家有机会重试。 在本教程中,你将禁用玩家的功能按钮,告知玩家他们已经输掉游戏,并加载关卡。
首先,你将创建一个游戏结束控件蓝图,告诉玩家他们已被淘汰。
添加游戏结束界面显示
要为游戏结束画面创建控件蓝图,请按照以下步骤操作:
在内容浏览器的AdventureGame > Designer > Blueprints > Widgets文件夹中,右键点击,找到用户界面(User Interface),然后选择控件蓝图(Widget Blueprint)。
在选取父类(Pick Parent Class)窗口中,点击用户控件(User Widget)。
将控件蓝图命名为
WBP_EliminationScreen并将其打开。
要设置游戏结束UI,请执行以下步骤:
在控制板(Palette)选项卡中,搜索canvas并将一个画布面板(Canvas Panel)拖到层级(Hierarchy)中的[WBP_EliminationScreen]上。 就像HUD一样,这个画布就是根控件。
画布上将显示游戏结束信息,并叠加一层模糊效果,使文本更易于阅读。 从控制板(Palette)选项卡中,拖动覆层(Overlay)以成为画布的子项。
选择覆层后,在细节面板的插槽(画布面板插槽)(Slot (Canvas Panel Slot)分段中,展开锚点(Anchors),并将最大值(Maximum)(X和Y)更改为
1。其他插槽属性(锚点(Anchors)下方)更改为偏移(Offset)设置。
当构建HUD时,你要将所有锚点保留在一个角落,因此如果屏幕尺寸发生变化,这些对象就仍会锚定到该锚点。 现在覆层会锚点到整个画布的边界盒体,从而会收缩或拉伸以匹配屏幕尺寸。
当你更改锚点设置时,编辑器会更改一些偏移值,以维持覆层面板的默认形状。 要删除此项,请将向右偏移(Offset Right)和底部偏移(Offset Bottom)更改为
0。 现在覆层将填满整个屏幕。从控制板(Palette)选项卡中,拖出一个背景模糊(Background Blur)控件,使其成为覆层(Overlay)面板的子项。
选择模糊效果后,在细节面板的插槽(覆层插槽)[Slot (Overlay Slot)]分段中,更改:
水平对齐为水平填充。
垂直对齐为垂直填充。
在外观(Appearance)分段中,将模糊强度(Blur Strength)更改为
5。从控制板(Palette)选项卡中,添加文本(Text)控件作为覆层(Overlay)的子项。
选中文本(Text)控件后,在细节面板的插槽(覆盖插槽)(Slot (Overlay Slot))分段中,更改:
水平对齐为水平居中对齐。
垂直对齐为垂直居中对齐。
在内容(Content)选项中,将文本(Text)更改为
You are deleted…restarting the level(你已经被淘汰…正在重启关卡)。转到外观(Appearance)部分,通过配置以下属性,使文本更清晰易读:
点击颜色和不透明度(Color and Opacity)旁边的色条,并为文本选取颜色。 本教程使用粉色(颜色十六进制sRGB =
FF4D7AFF)。展开字体(Font)标题栏,并将大小(Size)更改为
60。展开字体(Font)>轮廓设置(Outline Settings),并将轮廓大小(Outline Size)更改为
1。
12. 保存并编译蓝图。
为失败条件构建逻辑
现在你有了游戏结束的显示界面,我们还要修改角色类,在玩家耗尽生命值时显示它。 当出现这种情况时,执行会传递你之前使用的那个Branch节点的True结果。
要处理玩家失败,你需要:
禁用玩家输入,使玩家无法移动。
显示游戏结束界面。
在设定的时间后重新启动关卡。
要在玩家被淘汰时停止并加载游戏,请执行以下步骤:
在
BP_AdventurePlayer中,返回到角色蓝图中的伤害处理逻辑(从Event AnyDamage开始)。在Branch节点的True执行引脚之后,连接Do Once节点和Disable Input节点。
玩家在生命值耗尽后仍可能被击中,因此Do Once节点可以确保之后的逻辑仅执行一次。
对于Disable Input节点的Player Controller引脚,连接Get Player Controller节点(在节点操作列表的Game > Player分段中)。
有几个名为Get Player Controller的节点。 确保该节点具有Player Index输入引脚。 索引0是生成到关卡中的第一个玩家角色的默认索引。
禁用玩家控制器后,创建并显示游戏结束界面:
连接Create Widget节点。 在该节点中,将Class更改为
WBP_EliminationScreen。将控件节点的执行和Return Value 引脚连接到Add to Viewport节点。
添加时间延迟,获取当前关卡名称,然后加载该关卡:
在添加到Add to Viewport节点后,连接一个Delay节点并将Duration更改为
5秒。在Delay之后连接Get Current Level Name节点。
在Get Current Level Name之后连接一个Open Level (by Name)节点。
将Return Value引脚连接到Level Name引脚。 编辑器会自动添加一个字符串-to-name conversion节点。
保存并编译你的玩家蓝图。
现在,BP_AdventureCharacter事件图表的这一部分应与下图一致:
如果要将此逻辑复制到你的项目中,请首先删除节点的现有Damage处理组(包括Event AnyDamage和Event Destroyed逻辑)。
运行关卡以进行测试。 去踩到陷阱,让你的角色失去所有生命值,并确保游戏按预期重置。
为谜题添加危险因素
在谜题:开关和立方体中,你学习了如何设计能增加难度、紧张感、后果以及风险回报决策的游戏机制。 对玩家造成伤害的环境危险可以形成机制,让玩家的行为带来后果。 你可以使用尖刺陷阱为关卡中的早期谜题和障碍物增加危险性和额外后果,而开关驱动的火焰陷阱可以创建更具动态的谜题,让玩家与环境互动,从而打开安全的路径。
在设计游戏时,要减少开销并提高开发速度,关键是找到多种不同的方法来使用和组合Gameplay对象。 在本系列教程的上一小节中,我们介绍了基于开关的平台如何创建前进的道路。 在这里,同一个开关可以关闭火焰陷阱,为玩家显明道路。 这增加了关卡的多样性,也不需要无穷无尽的独特系统。
与本教程系列之前创建的门与钥匙机制类似,火焰陷阱也是一种机制,用来控制玩家的行进速度以及能够进入哪些区域。
创建带有火焰陷阱的迷宫谜题
在Room 2中,你将结合开关和火焰陷阱来构建一个神奇的谜题,玩家必须小心地排除所有危险,找到并收集最后一把钥匙。
先在纸上画出谜题的草图通常会对你有所帮助。 由于陷阱的大小为1m x 1m,示例Room 2可以容纳7 x 9的陷阱网格。 首先绘制一条穿过网格并在钥匙处结束的路径。 然后,将路径划分为多个片段,并放置开关来控制每个片段。
要增加难度并创造更多的惊喜和出其不意的效果,请添加阻挡视线的建筑功能。 例如,将开关放置在墙壁或柱子后面,这样玩家就必须沿路径发现它们。
此循环路径使玩家能够看到钥匙,以便在走过路径的第一片段时发现目标。
完成计划后,开始在关卡编辑器中规划谜题。
创建通向钥匙和粗模形状的路径后,用火焰陷阱填充房间的其余部分,以遮挡正确的路径。
在大纲视图中重命名你的关卡对象,以便清楚地显示每个控制开关对应哪个火焰陷阱。 例如,如果BP_Switch1会关闭三个陷阱,则将它们分别命名为BP_FireTrap_S1_0、BP_FireTrap_S1_1和BP_FireTrap_S1_2。 将额外的火焰陷阱重命名为BP_FireTrap_Extra之类的名称,以表明它们不是谜题的一部分。
如果需要,你可以在钥匙下面添加一个最终开关,能关闭沿途的一些陷阱,从而帮助玩家在完成谜题时离开。
要经常测试你的谜题,注意视野、挫败点和可能的捷径。 找好朋友来帮忙测试;他们可能会发现你未预料到的漏洞。 在游戏测试期间,你可能会发现到需要一些调整,做出阻挡效果或阻止玩家直接跳过谜题的某些部分。
如果你发现了这种情况,你有两种选择:
重新排列路径或谜题。
添加更多的阻挡建筑。
提高火焰伤害,让偏离路径的玩家遭受更严重的后果。
保留这个漏洞,但增加玩家相应的付出,为玩家提供自主选择权。 他们可以选择花更多时间开辟安全的路径,也可以牺牲生命值来冲向钥匙。
在示例关卡的谜题中,我们在钥匙的拱门下方添加了一些碎石,这样玩家就可以看到钥匙,但无法直接跳到钥匙处。 我们还隐藏了开关,不仅是为了一些好玩的惊喜,也是为了防止玩家直接跳过路径的这一部分。
为障碍物添加尖刺
让我们向之前的谜题添加尖刺,以增添失败的后果
从Room 1的谜题开始。 对于第一个移动平台,降低木桩的高度,以便在玩家失败时,他们可以重新爬上来重试。 引入新机制时,要让玩家有足够的空间在安全的环境中学习,以便他们试错
同样在起始房间中,你可以在第一个钥匙下的坑中添加一些尖刺。 玩家可以在前两个平台上练习跳跃,为最后一次跳到钥匙处的、风险更高的跳跃做好准备。 如果玩家能毫发无伤地拿到第一个钥匙,那可真是太厉害了。
玩家已经了解了基础操作,也会在平台和开关上练习了跳跃技巧,现在我们可以添加效果了。 在第二个平台或第三个按钮下,放置一些尖刺陷阱。 现在你已经提高了游戏的刺激性,因为玩家掉落时会受到伤害,但他们可以快速离开陷阱,将伤害降到最低并继续游戏。
最后,对于最后一个平台和开关,我们继续提高危险性。 用尖刺覆盖下面的区域,这样玩家就必须跑得更远才能避开尖刺,因此会受到更多伤害。 此时玩家应该对这个机制更加熟悉了,而且犯错的后果也能接受,因为他们之前已经练习过了。
此设计旨在向玩家介绍游戏机制的常见结构:
介绍:第一个学习游戏机制的安全平台。
开发:第二个平台和立方体以中等风险测试玩家技术的成长。
变化:最后的平台会将危险升级,并增加了新的移动方向,变成了紧张刺激的挑战。
就像你在谜题:移动平台中的Gameplay设计课程中学到的那样,通过在整个谜题中逐步提升危险性,你可以平衡游戏的公平性和刺激性。
更改陷阱的伤害
你可以决定通过增加或减少一种陷阱类型的伤害来调整难度关卡。 你可以通过以下两种方式执行此操作:
在大纲视图中,搜索"spike"或"fire",并选择该类型的所有陷阱。 在细节面板中,根据需要更改Setup > Base Damage。 使用这种方法时,请记住还要更改关卡中该陷阱的所有新实例的基础伤害。 或者,通过复制现有陷阱向关卡新增陷阱实例,从而避免编辑每个新实例。
或者
打开一个子陷阱蓝图,并转至其构造脚本(Construction Script)选项卡。 你无法在“我的蓝图”面板中编辑继承的变量,但可以在图表中设置变量。 在这两个Construction Script节点之后,连接Set Base Damage节点。 在节点中,根据需要更改Base Damage数值。
为确保玩家可预测你的Gameplay对象,请确保一种类型的所有陷阱造成的伤害相同。
在教程的示例关卡中,火焰陷阱每秒造成5点伤害,而尖刺陷阱实例修改为每秒造成10点伤害。
尝试示例关卡
如果不想自行搭建,而是希望直接使用本节教程中设计的房间部分,可以复制下方的代码片段。
Room 2的粗模搭建
此文本片段包含Room 2的地板、墙壁和为创建此房间的谜题而添加的新粗模形状。 在大纲视图中,所有形状都在名为Room2的文件夹中。
Begin Map
Begin Level
Begin Actor Class=/Script/Engine.TextRenderActor Name=TextRenderActor_19 Archetype="/Script/Engine.TextRenderActor'/Script/Engine.Default__TextRenderActor'" ExportPath="/Script/Engine.TextRenderActor'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19'"
Begin Object Class=/Script/Engine.TextRenderComponent Name="NewTextRenderComponent" Archetype="/Script/Engine.TextRenderComponent'/Script/Engine.Default__TextRenderActor:NewTextRenderComponent'" ExportPath="/Script/Engine.TextRenderComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19.NewTextRenderComponent'"
End Object
Begin Object Class=/Script/Engine.BillboardComponent Name="Sprite" Archetype="/Script/Engine.BillboardComponent'/Script/Engine.Default__TextRenderActor:Sprite'" ExportPath="/Script/Engine.BillboardComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19.Sprite'"
End Object
Begin Object Name="NewTextRenderComponent" ExportPath="/Script/Engine.TextRenderComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.TextRenderActor_19.NewTextRenderComponent'"
Text=NSLOCTEXT("[3C535F7772EB3B3657484B5E2D5B925D]", "2347F80B407C68C27836E990A20143CF", "Room 2")
HorizontalAlignment=EHTA_Center
请按照以下步骤,复制Room 2的所有粗模:
移除Room 2中已有的物品(或Hallway 2末端的物品):
使用大纲视图选择Room 2的现有内容:右键点击
Room2文件夹,然后选择选择(Select)> 直接子项(Immediate Children)。 按Delete。或者将视口切换到顶部正交视图,以手动选择和删除现有的房间。
点击复制完整代码片段(Copy Full Snippet)。
在虚幻编辑器中,确保视口或大纲视图为激活的面板(在视口或大纲视图内点击任意位置后按Esc),然后按Ctrl+V粘贴。
你的关卡和大纲视图应如下所示:
Room 2的开关、陷阱和钥匙
此文本片段包含谜题的开关、陷阱和红色钥匙。 在大纲视图中,所有对象都在名为Room2的文件夹中。
要在项目之间复制蓝图实例,父蓝图资产必须完全相同,并且文件名称和位置必须相同。 如果你在项目中更改了蓝图的组件、变量名称或属性,代码片段可能无法按预期复制,你需要手动设置这些关卡对象。
Begin Map
Begin Level
Begin Actor Class=/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C Name=BP_FireTrap_C_261 Archetype="/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.Default__BP_TrapFire_C'" ExportPath="/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261'"
Begin Object Class=/Script/Engine.SceneComponent Name="DefaultSceneRoot" Archetype="/Script/Engine.SceneComponent'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C:ICH-DefaultSceneRoot_GEN_VARIABLE'" ExportPath="/Script/Engine.SceneComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.DefaultSceneRoot'"
End Object
Begin Object Class=/Script/Engine.StaticMeshComponent Name="TrapBase" Archetype="/Script/Engine.StaticMeshComponent'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C:TrapBase_GEN_VARIABLE'" ExportPath="/Script/Engine.StaticMeshComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.TrapBase'"
End Object
Begin Object Class=/Script/Engine.BoxComponent Name="TrapTrigger" Archetype="/Script/Engine.BoxComponent'/Game/AdventureGame/Designer/Blueprints/Traps/BP_TrapFire.BP_TrapFire_C:TrapTrigger_GEN_VARIABLE'" ExportPath="/Script/Engine.BoxComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.TrapTrigger'"
End Object
Begin Object Name="DefaultSceneRoot" ExportPath="/Script/Engine.SceneComponent'/Game/AdventureGame/Designer/Lvl_Adventure.Lvl_Adventure:PersistentLevel.BP_FireTrap_C_261.DefaultSceneRoot'"
要设置谜题的蓝图,请执行以下步骤:
点击复制完整代码片段(Copy Full Snippet)。
在虚幻编辑器中,确保视口或大纲视图为激活的面板,然后按Ctrl+V。
检查每个开关的Setup属性,如有必要,将每个开关重新连接到相应的火焰陷阱:
在大纲视图中的
Room2文件夹中,点击BP_Switch4。在细节面板的Setup分段中,展开交互对象列表(Interact Object List)。
对于列表中的每个元素,点击下拉菜单,搜索
S4,然后选择一个带有S4标签的火焰陷阱。对每个开关重复这些步骤:
BP_Switch5触发BP_FireTrap_S5_0-7BP_Switch6触发BP_FireTrap_S6_0-3BP_Switch7触发BP_FireTrap_S7_0-4BP_Switch8触发BP_FireTrap_S8_0-3BP_Switch9在钥匙下触发BP_FireTrap_S9_0-4
你的关卡和大纲视图应如下所示:
下一步
接下来,你将学习如何在游戏中添加另一种常见的危险因素——敌方NPC! 了解如何创建AI敌方角色,并将寻路网格体添加到关卡,以便敌人能够找到玩家并对其造成伤害。