在本节中,你将创建第一个Gameplay物体:钥匙蓝图。
你将使用蓝图可视化脚本来为关卡中的Gameplay物体创建功能。 虚幻引擎中的蓝图是一种特殊的资产,它既有实体形态,又具备特殊功能(例如允许玩家拾取)。
蓝图可视化脚本系统能够让用户无需编写代码,即可通过基于节点的界面来创建Gameplay物体的行为。
首先,你需要定义钥匙在游戏中的Actor形态,并为其添加组件,从而呈现三种不同的钥匙(黄色椭圆形、蓝色矩形、红色圆锥体)。 无需为每种变体都创建单独的资产,蓝图能让你将所有选项都集成在同一个资产里。
接下来,你将为钥匙添加行为——让玩家角色能够将其拾取。 拾取物体是一种极为常见的Gameplay机制。
以下是你将创建的所有资产概览,用于制作一把拥有三种不同外观选项的钥匙,并允许玩家角色拾取该钥匙:
开始之前
请确保你已掌握设计解谜冒险游戏 前几节讲述的以下内容:
你需要准备好在项目设置与关卡粗模搭建中创建的下列资产:
一个已完成粗模搭建的关卡。
定义钥匙类型与属性
在创建钥匙蓝图前,要先定义一些关键数据,蓝图将依据这些数据来创建红、黄、蓝三种变体。
为了表示游戏中的不同钥匙类型,你将用到枚举(Enumeration) 和结构体(Structure) 这两种资产。
| 资产类型 | 说明 |
|---|---|
枚举 | 枚举(也称Enum)用于存储一个可在项目全局使用的唯一值列表。 对于钥匙,你将使用一个枚举来定义所有可选的钥匙类型(黄色椭圆形、蓝色矩形、红色圆锥体)。 |
结构体 | 结构体(也称Struct)用于将相关联的信息归类分组。 对于钥匙,你将使用一个结构体来存放它的所有属性:一个网格体(3D模型),以及应用到该网格体上的材质颜色(红、黄、蓝)。 |
每个枚举器好比是容器的标签,而结构体就是容器里存放的东西。
在枚举中定义钥匙类型
首先,创建一个枚举资产来定义钥匙的几种变体:红、黄、蓝。
请按照以下步骤,创建枚举资产:
打开内容浏览器,或通过虚幻引擎左下角的内容抽屉(Content Drawer) 按钮开启一个内容抽屉。
为本教程中将要创建的蓝图及辅助资产创建一个存放目录。 进入Content > AdventureGame > Designer文件夹。 在该文件夹中右键点击,然后选择新建文件夹(New Folder)。
将新文件夹命名为
Blueprints。在Blueprints 文件夹内,再创建一个名为
Core的文件夹。在Core 文件夹中右键点击,依次选择蓝图(Blueprint) > 枚举(Enumeration)。 将新资产命名为
Enum_KeyType。双击该资产,即可在新窗口中打开它。
此枚举资产内含一个枚举器选项列表。
请按照以下步骤,向该枚举中添加钥匙类型:
点击添加枚举器(Add Enumerator) 按钮三次,为列表添加三个新的枚举项。
将第一个枚举器的显示名称(Display Name) 改为
Blue。 将第二个改为Yellow,第三个改为Red。点击窗口左上角的保存(Save) 按钮,保存枚举资产。 也可以使用快捷键CTRL + S。
每添加一个枚举器,就相当于在列表中增加一个选项。 蓝、黄、红这三个值将用于区分不同的钥匙类型。
与蓝图不同,数据资产无需编译,因为它们本身不包含任何待编译的功能。
在结构体中定义钥匙属性
接下来,创建一个结构体来定义区分各个钥匙类型的属性:网格体形状和颜色。
请按照以下步骤,构建结构体(Struct)资产:
再次打开内容浏览器,并确保当前路径为Content > AdventureGame > Designer > Core。
在Core 文件夹内右键点击,依次选择蓝图 > 结构体(Structure)。 将该资产命名为
Struct_KeyData。双击此新资产,即可在新窗口中打开其属性面板。
该结构体在创建时会默认带有一个名为MemberVar_0的变量。 点击添加变量(Add Variable) 来添加第二个变量。
将第一个变量命名为
Key Material,第二个变量命名为Key Mesh。每个变量都有一种与之对应的数据类型。 该类型默认为布尔值(即True或False)。 你需要更改这两个变量的类型。
找到Key Material变量,点击其类型下拉菜单(当前显示为Boolean)。 在搜索框中输入
material instance,将鼠标悬停于Material Instance上,然后选择对象引用(Object Reference)。重复以上步骤,将Key Mesh 的变量类型改为Static Mesh > Object Reference。
保存此结构体资产。
至此,你已成功为每种钥匙类型创建了两个属性——用于设定钥匙颜色的“Key Material”,以及用于设定钥匙形状的“Key Mesh”。
你已经完成了钥匙数据的定义工作。 接下来,你将设置钥匙的颜色,并着手构建各种类型的钥匙。
创建钥匙颜色
现在你已拥有蓝、黄、红三种钥匙类型的数据,接下来将创建对应颜色的材质,并将它们分别指定给各类钥匙。
在虚幻引擎中,材质决定了物体表面的视觉效果。 它能控制颜色、纹理、光泽度、透明度等诸多方面。 材质实例是一种材质的副本,它继承了父材质的基础属性,但允许你覆盖颜色、纹理等特定设置,从而避免了从零开始创建全新材质的麻烦。
在本例中,你将创建一个基础材质,用它来定义游戏中所有钥匙的通用属性。 然后,你将基于该材质创建两个材质实例,它们会继承所有属性,但颜色将被覆盖。
本节只会简要介绍材质的创建步骤,以便你在后续教程中使用,不会深入讲解材质的原理。
请按照以下步骤,创建带颜色的材质资产:
打开内容浏览器。 进入Content > AdventureGame > Designer 文件夹。
在Designer 文件夹内右键点击,并选择新建文件夹。 将该文件夹命名为
Materials。进入Materials 文件夹。 在该文件夹内右键点击,选择材质(Material) 以创建材质资产。
将此材质资产重命名为
M_BasicColor。本教程的示例关卡使用
M_前缀作为命名约定,用于识别材质资产。双击该材质即可将其打开。 此时将在一个新窗口中打开材质编辑器(Material Editor)。
材质编辑器是一种基于节点的编辑器,这意味着它在某些方面与蓝图可视化脚本的构建方式类似。 你会看到一个名为M_BasicColor的节点,这是用于更改该材质属性的主节点。
底色(Base Color) 属性决定了此材质的颜色。 点击底色属性旁的灰色方块即可手动设定颜色。
与其使用“颜色拾取器”(Color Picker),不如创建一个颜色(Color) 参数节点,这样一种材质就能呈现出多种颜色。 创建参数的效果等同于添加变量,即把材质颜色变成一个能在材质实例中编辑的参数。
请按照以下步骤,创建颜色参数节点:
在底色属性旁,可以看到一个引脚(Pin)。 点击引脚,然后拖动到图表中的空白处。
在弹出的列表中,于搜索框内键入
VectorParameter,并选择矢量参数(VectorParameter)。操作完成后,会生成一个包含颜色拾取器的新节点。 矢量型变量有三个值,正好可以用来定义一种颜色的RGB值。
节点创建后,其默认名称Param会处于高亮状态。 把节点改名为颜色,这样在材质实例中会更易于辨识。
若“Param”没有高亮,可以先点击节点,再点击节点名称来重命名。
在新建的颜色节点上,点击默认值(Default Value) 属性旁的方格图案,以打开颜色拾取器。
在“十六进制sRGB”(Hex sRGB)字段里,把值改为黄色的
F7DE0000,然后点击“确定”。点击保存(Save) 后关闭此材质资产。
下一步是创建材质实例,这样就能在不重做主材质的基础上,添加更多的颜色变体。
请按照以下步骤,为不同钥匙颜色创建三个材质实例:
打开内容浏览器,在其中右击之前创建的
M_BasicColor资产。 在右键菜单的靠前位置,点击创建材质实例(Create Material Instance)。把此材质实例资产命名为
M_BasicColor_Red。 双击资产将其打开。可以看到,这个窗口和材质编辑器有所不同。 这是因为材质实例无需像材质那样提供全套编辑功能,它的核心作用是修改基础材质中已定义的参数。
在细节面板中,找到顶部的参数组(Parameter Groups)分类,并将其下的全局向量参数值(Global Vector Parameter Values)展开。
此时会看到一个未启用的颜色参数,它对应着在基础材质中添加的那个VectorParameter节点。 勾选“颜色”参数旁边的选框,从而启用并覆盖该参数。
点击“颜色”参数旁的色板,将其十六进制sRGB值设为
F7005A00。 这样,材质实例的颜色就变成了亮红色。接下来,请自行完成剩余步骤! 重复以上流程,再创建两个材质实例:
创建名为
M_BasicColor_Blue的材质实例。 将“颜色”参数覆写为十六进制sRGB =00AFF700,然后保存该资产。创建名为
M_BasicColor_Yellow的材质实例。 此实例直接沿用基础材质的颜色,保存资产即可。
材质实例的参数继承自其父材质,所以除非主动覆盖,否则参数值将始终与父材质保持一致。 举例来说,如果打开M_BasicColor材质并修改了颜色,那么M_BaseColor_Yellow这个材质实例的颜色也会随之改变。而蓝色和红色的材质实例则会因为参数已被覆盖,而维持原色不变。
创建钥匙蓝图
准备工作已经完成,现在开始创建钥匙蓝图。 钥匙蓝图是一种资产,可以将其添加到关卡中,从而创建一个可被玩家拾取的实例化Actor。
请按照以下步骤,为钥匙创建一个新的蓝图类:
打开内容浏览器,进入Content > AdventureGame > Designer > Blueprints文件夹。
新建一个名为
Key的文件夹。打开Key文件夹。 在文件夹内右击,然后选择蓝图类(Blueprint Class)。
在“选取父类”(Pick Parent Class)窗口中,选择Actor。
把这个新Actor命名为
BP_Key,然后双击将其打开。在本教程的示例关卡中,使用
BP_前缀作为蓝图类的命名约定。
Actor是一种常见的父类,适用于所有可被放置到关卡中的物体。它不像“角色”(Character)父类那样自带移动等功能,但可以用来创建交互和实现逻辑。
若想将窗口停靠在主编辑器内,只需将其标签页拖至关卡标签页旁即可。
为了让钥匙蓝图正常运行,还需要为其添加几个要素:
一个静态网格体,用作钥匙在项目中的视觉形象。
一个碰撞体积,用于检测玩家是否进入可拾取钥匙的范围。
一种用于区分钥匙类型的方式。
一段游戏逻辑,用来定义玩家与钥匙碰撞时触发的事件。
所谓碰撞,即是在运行时检测两个物体是否发生接触。 盒体、胶囊体和球体碰撞是用于实现这些检测的几种常用形状。
设置钥匙组件
首先来设置钥匙的组件,这样才能在游戏世界中放置实体并与之交互。
请按照以下步骤,为钥匙添加碰撞组件和网格体形状:
在
BP_Key中,切换到视口 标签页。在左上方的组件(Components)面板中,点击添加(Add),然后搜索并选中胶囊体碰撞(Capsule Collision)。
这就是玩家拾取钥匙时所接触的碰撞体积。 若没有这个组件,玩家将无法检测到钥匙。
当然也可以直接在钥匙网格体上添加碰撞,但使用独立的碰撞形状有助于平滑复杂的几何轮廓,进而提升碰撞检测的准确度和游戏性能。
选中胶囊体组件,再次点击添加。 这一次,搜索并选择一个球体(Sphere)基本形状,然后将其改名为
KeyMesh。先选中胶囊体组件再添加球体网格体的操作,会使网格体成为胶囊体的子组件,胶囊体则是网格体的父组件。 子组件将继承其父组件的所有属性。
设置KeyMesh组件的步骤如下:
选择KeyMesh组件。 在细节面板中,找到变换(Transform)类别。 将缩放(Scale)旁边的值分别改为
0.3、0.3和1.0。此操作会将网格体在两个轴向上压扁,使其变为椭圆形。
在碰撞(Collision)类别下,把碰撞预设(Collision Presets)设为无碰撞(NoCollision)。
由于已经使用胶囊体组件处理碰撞,此处关闭网格体自身的碰撞,能确保玩家角色在收集钥匙时不会因撞上静态网格体而弹开。
设置胶囊体组件的步骤如下:
选择胶囊体组件。 在细节面板的变换类别下,把位置(Location)设为
0.0、0.0、80.0。这样可以使钥匙悬浮在空中。 由于网格体是子组件,会继承父组件的所有属性,因此它会跟随胶囊体一起移动。
在形状(Shape)类别下,把胶囊体半高(Capsule Half Height)设为
60.0。 此操作会拉伸碰撞体积,使其能更好地包裹住整个网格体。
在组件面板中,选中默认场景根节点(DefaultSceneRoot)。 点击添加,然后选择旋转运动(Rotating Movement)。 该组件能让钥匙缓慢旋转,使其在场景中更加醒目。
保存(Save)并 编译(Compile) 蓝图。
设置钥匙属性
钥匙本身也需要存储一些信息,比如它是什么类型的钥匙,以及该类型对应的材质和网格体分别是什么。
这项设置需要用到之前创建的“枚举钥匙类型”(Enum Key Type)和“结构体钥匙数据”(Struct Key Data)。
请按照以下步骤,为蓝图添加一个钥匙类型变量:
在组件面板的下面是我的蓝图(My Blueprint)面板。 在变量(Variables)部分,点击加号(+)按钮添加一个新变量。
把变量命名为
KeyType。它的默认类型是布尔值。 点击类型下拉菜单,搜索并选中枚举键类型(Enum Key Type)。 这个变量类型正是之前创建的枚举,现在可以派上用场了。 这意味着KeyType变量的值只能是红、黄或 蓝中的一个。
在蓝图中,变量类型也叫引脚类型(pin type),因为节点上的变量都显示为引脚。
点击KeyType变量旁边的眼睛图标,将其设为公开可编辑变量。 这一步至关重要,只有这样,后续才能在虚幻编辑器中修改该变量的值,从而设定关卡中每个钥匙实例的类型。
选中KeyType变量。 在细节面板中,找到类别(Category)属性,删除旁边的Default,然后输入
Setup。这样,KeyType属性就会显示在细节面板中名为Setup的分类下。
每一种钥匙类型都应对应一种形状和颜色的组合。 下一步将创建一个“映射”(Map)变量来定义这些组合。
请按照以下步骤,设置一个能将钥匙类型映射到对应形状和颜色的变量:
在我的蓝图面板中,添加一个名为KeyMap的新变量,类型同样设为枚举键类型。
选中KeyMap变量,在细节面板中可以看到,类型下拉菜单旁还有一个菜单,用于设定变量的容器类型(container type),它决定了变量能存储多少个值。 将容器类型改为映射(Map)。
当容器类型设为映射后,其旁边会出现一个新的类型下拉菜单。 这个下拉菜单用于指定映射中存储的数据类型。 此前已在结构体中定义好了钥匙数据,所以这里只需点击下拉菜单,并将数据类型设为Struct_KeyData。
编译蓝图,这样才能开始为KeyMap填充数据,即为每个KeyType选项配置对应的材质和网格体。
在细节面板中,找到默认值类别。
点击Key Map旁的+按钮,为该映射添加一个新元素。
将钥匙类型从默认的蓝色改成其他颜色。 如果不先修改,可能会因为默认的钥匙类型已经存在而无法添加新元素。
重复此操作两次,创建总共三个元素。
添加完三个映射元素后,用以下数值来设置你的钥匙类型:
键类型 钥匙材质 钥匙网格体 红色
M_BasicColor_Red椎体
黄色
M_BasicColor_Yellow球体
蓝色
M_BasicColor_Blue正方体
完成后,KeyMap变量的设置应与下图一致:
保存(Save)并 编译(Compile) 蓝图。
最后一步是创建一个变量,用于在玩家角色触碰钥匙时,保存对该角色的引用。
可按照以下步骤,创建一个能存储其他Actor引用的变量:
在变量(Variables)区域中,新建一个变量并将其命名为
OtherActor。将该变量的类型设置为Actor > 对象引用(Actor > Object Reference)。
在细节面板中,将容器类型(Container Type)设置为单个(Single)。此设置的原因在于,每次与钥匙交互的Actor只有一个(即玩家),因此无需使用其他容器类型。
完成上述设置后,钥匙的变量部分应如下图所示:
测试钥匙功能
接下来,实际测试一下钥匙,以确认其当前在游戏中的表现。
切换回关卡编辑器,从内容浏览器中找到BP_Key资产并将其拖放到关卡中。 至此,一个可随时在游戏中实例化的蓝图就创建完成了,这是一个重要的阶段性成果。 不过,此时钥匙在场景中仍显示为灰色。
在选中钥匙的状态下,查看其细节面板。 在面板中找到之前创建的设置(Setup)类别,然后定位到钥匙类型(Key Type)属性。 尽管可以将该属性的值在蓝色、黄色和红色之间切换,但钥匙的灰色椭圆形状并不会因此改变。
出现这种情况的原因在于,尽管已经为钥匙添加了组件和数据,但它们之间还没有逻辑关联。 这正是蓝图可视化脚本发挥作用的地方。通过它构建由节点和连线组成的逻辑,可以在蓝图内部传递信息并据此执行操作。
通过蓝图函数设置钥匙的值
下一步是创建一个函数,以连接KeyMap和KeyMesh组件,实现根据钥匙类型自动设置其网格体形状和材质颜色的功能。
函数(Function)是一套可复用的蓝图节点集合,用于完成某项特定任务。 使用函数不仅能让节点图表更有条理,还能在需要时多次执行(即“调用”)同一段逻辑,而无需重复搭建。 你可以借助函数,从其他蓝图触发该部分蓝图逻辑的执行。
我们不会在钥匙蓝图中直接创建这个函数,而是将其置于一个新的蓝图函数库(Blueprint Function Library)中。这是一种专门存放可复用函数集合的蓝图资产。 库中的函数并不与任何特定的蓝图或Actor相关联。 相反,它们在整个项目中是全局可访问的。 函数库能将实用函数集中管理,避免在多个蓝图间反复复制粘贴同一段逻辑。
请按照以下步骤,创建一个蓝图函数库并添加新函数:
打开内容浏览器,并进入Content > AdventureGame > Designer > Core路径。
在Core文件夹空白处右键点击,在菜单中选择蓝图(Blueprint),然后点击蓝图函数库。 将新建的资产命名为
BPL_FPGame,然后双击打开。打开编辑器后,在我的蓝图(My Blueprint)面板的函数(Functions)区域中,可以看到一个系统自动创建并已高亮选中的新函数。 将该函数命名为
fnBPLSetKey。本教程的示例项目遵循一套命名规范:
BPL代表函数来源于蓝图函数库,而fn是函数名的前缀。 这种规范有助于直观地理解SetKey的性质及其来源,同时也方便在节点操作列表中快速搜索到该函数。
下一步是为该函数配置所需的输入和输出参数。
输入(Input)是调用函数时传递给它的值,函数将基于这些值进行运算。 它们的行为与变量十分相似。 fnBPLSetKey函数的功能是处理KeyType、KeyMap和KeyMesh三者间的逻辑,因此需要将这三者都设为输入。
输出(Output)则是函数执行完毕后返回给调用方的信息,通常是运算结果。 对于fnBPLSetKey函数而言,它无需任何输出。
请按照以下步骤,为fnBPLSetKey函数添加入参:
选中fnBPLSetKey函数。 在细节面板中,找到输入类别,并点击旁边的+按钮来添加一个新输入。
和变量一样,每个输入也需要定义其名称、变量引脚类型和容器类型。
将此输入的名称改为
静态网格体数组(Static Mesh Array)。将其类型设置为静态网格体组件 > 对象引用(Static Mesh Component > Object Reference)。 此时观察函数的节点图表,会发现紫色的函数入口节点上出现了一个新的引脚,其样式精确地反映了刚创建的输入类型(静态网格体数组)。
点击类型旁边的容器类型下拉菜单,并选择数组(Array)。
数组是一种能在单个容器中存储多个同类型值的变量。 存储在数组中的每个值被称为一个数组元素。
接下来,设置另一个输入,使其与钥匙的KeyMap属性相匹配:
添加一个新输入,命名为
KeyMap。点击引脚类型(Pin Type)下拉菜单,将其设置为枚举键类型(Enum Key Type)。
点击容器类型下拉菜单,并选择映射(Map)。
点击值类型(Value Type)下拉菜单,将其设置为结构体钥匙数据(Struct Key Data)。
接着,设置Key Type输入:
添加一个名为
Key的新输入。将其容器设为单个,类型保持为枚举键类型。
完成后,三个输入参数应如下图所示:
输入参数配置完毕,接下来开始构建函数的节点逻辑。 在图表面板中,可以看到函数入口节点fnBPLSetKey上,已经带有刚刚创建的静态网格体数组、Key Map和Key这三个输入引脚。
蓝图图表导航操作:
平移(Pan):按住鼠标右键并拖动。
缩放(Zoom):滚动鼠标滚轮。
请按照以下步骤,为函数添加逻辑,以实现通过新的Key Mesh来设置钥匙形状的功能:
从该节点的三角形执行(exec)引脚上拖出连线,搜索并选择For Each Loop节点。 这样就创建了一个新的节点,并自动连接至fnBPLSetKey节点。
For Each Loop节点的作用是遍历数组中的每一个项,并对其执行指定操作。 任何连接到“循环主体”(Loop Body)执行引脚的逻辑,都会为数组中的每个元素执行一次。 待循环遍历完所有元素后,执行流将从“已完成”(Completed)引脚继续。
将fnBPLSetKey节点的静态网格体数组引脚连接到For Each Loop节点的数组引脚。
尽管当前钥匙只有一个网格体,但fnBPLSetKey的输入被设计为静态网格体数组,是为了使其能够兼容处理拥有多个网格体的各类关卡物体。 例如,在本系列教程的下一部分中,将要处理的门蓝图就包含左右两扇门,即两个静态网格体。
接下来,从fnBPLSetKey节点的Key Map引脚拖出连线,搜索并添加一个查找(Find)节点。 该节点能根据给定的Key Type,从KeyMap中查询出对应的网格体和材质信息。
在Find节点的蓝色输出引脚上右键点击,然后选择拆分结构体引脚(Split Struct Pin)。
此操作会将原输出引脚拆分为钥匙材质(Key Material)和钥匙网格体(Key Mesh)两个引脚,它们分别对应
Struct_KeyData结构体中的两个变量。将fnBPLSetKey节点的Key引脚,连接到Find节点的青绿色Key输入引脚。
在For Each Loop节点上,从循环主体引脚拖出连线,搜索并添加一个Is Valid节点(位于结构体类别下)。 注意,应添加旁边带有问号图标(?)的Is Valid节点,该版本专用于检查结构体这类值的有效性。
该节点用于检查传入函数的网格体形状是否有效。 如果有效,则同时设置该对象的静态网格体和材质。 如果无效,则只更新其材质。
将Find节点的钥匙网格体引脚,连接到Is Valid节点的输入对象(Input Object)引脚。
从Is Valid节点的Is Valid执行引脚拖出连线,并关闭上下文关联(Context Sensitive)选项。
搜索并添加设置静态网格体(Set Static Mesh)节点。
从For Each Loop节点拖出数组元素引脚,并将其连接到设置静态网-网格体节点的目标(Target)引脚。
目标引脚决定了该节点将对哪个实体生效。 此处的意图是在KeyMesh上执行“设置静态网格体”操作,因此目标应为“静态网格体数组”中的当前元素。
从Find节点拖出钥匙网格体引脚,并将其连接到设置静态网格体节点的新建网格体(New Mesh)引脚。
完成后,函数的图表应如下图所示:
钥匙的新网格体形状设置逻辑已完成,接下来只需设置其新材质。
请按照以下步骤,添加用于设置钥匙新材质颜色的逻辑:
从设置静态网格体节点的执行引脚拖出连线,搜索并创建设置材质(Set Material)节点(位于渲染 > 材质类别下)。
将其目标引脚连接到For Each Loop节点的数组元素引脚。
将其材质引脚连接到Find节点的钥匙材质引脚。
为确保在未提供有效网格体的情况下也能设置材质,需要将Is Not Valid引脚连接到设置材质节点的执行引脚。 可以添加两个连接点来调整连线的走向。
保存(Save)并 编译(Compile) 蓝图。
此时,完整的fnBPLSetKey函数应如下图所示:
若要将这组节点复制到自己的项目中,可点击复制完整代码片段(Copy Full Snippet),然后在蓝图对应图表的空白处点击,最后按Ctrl+V粘贴。 粘贴后,需要手动将函数入口节点的输出引脚连接到For Each Loop和Find节点的相应输入引脚。
初始化钥匙
函数已经创建完毕,现在可以在钥匙蓝图内部调用它了。 首先要做的,是根据为钥匙指定的KeyType来初始化它。
对蓝图关卡物体进行初始化(Initialize),指的是在物体被创建时(无论是在视口中放置,还是在游戏开始时生成)就对其进行初始设置。
请按照以下步骤,初始化钥匙:
从构造脚本(Construction Script)节点的执行引脚拖出连线,搜索并添加之前创建的fnBPLSetKey函数节点。
该函数节点需要静态网格体数组、Key Map和Key三个输入,这些数据都将由
BP_Key蓝图自身提供。在我的蓝图面板中,于变量部分的设置类别下,将KeyType变量拖入节点图表,放置在函数节点旁边。
此时会弹出一个菜单,询问是想获取(Get)还是设置(Set)该变量的值。 在当前情况下,需要读取钥匙的类型,因此选择获取。
将新创建的获取钥匙类型(Get Key Type)节点的输出引脚,连接到Fn BPLSet Key节点的Key输入引脚。
对KeyMap变量重复上述过程。 将其拖入节点图表并选择创建Get节点。 将该节点的输出引脚连接到Fn BPLSet Key节点的KeyMap输入引脚。
接下来,从组件(Components)面板中将KeyMesh拖入图表,并选择创建Get节点。
Key Mesh节点输出的是单个静态网格体组件引用,而函数节点的输入需要一个数组。 虚幻引擎会自动处理这种转换:只需将Key Mesh引脚直接连接到Fn BPLSet Key节点的静态网格体数组输入引脚。
保存并编译蓝图。
此时,钥匙的构造脚本应如下图所示:
如果是将代码片段粘贴到项目中,则需要手动将FnBPLSetKey节点的执行输入引脚连接到构造脚本节点的执行输出引脚。
测试钥匙的功能
现在可以测试刚刚在钥匙和新函数中实现的颜色切换功能了。
关闭蓝图编辑器窗口,回到主关卡编辑器界面。
因为Key Type的默认值是Blue,所以关卡中的钥匙实例应该已经自动变成了蓝色的矩形。
选中关卡中的钥匙Actor,在细节面板的设置部分下,尝试将Key Type的值在黄色和红色之间切换。 在切换属性值时,应该能看到关卡中的钥匙实例实时地更新其颜色和形状。
为玩家角色授予钥匙
游戏需要一套机制,首先要让玩家能够拾取钥匙,其次要让其他物体能检测到玩家当前持有的钥匙。 实现这套机制,我们将用到蓝图接口(Blueprint Interface)。
利用蓝图接口实现蓝图间的通信
蓝图接口是一种资产,它本身只存储一个函数声明列表,任何实现了该接口的蓝图都可以调用这些函数。 实现(implement)接口,意味着赋予蓝图一种能力,使其可以对一组共享的事件(或称消息)作出响应。
假设在一个同时存在玩家和NPC角色的游戏中,钥匙必须能够准确识别交互对象,确保只有玩家角色才能触发拾取行为。 要做到这一点,就需要创建一个蓝图接口,并由BP_AdventureCharacter玩家蓝图来实现它。 这个接口就像一张“通行证”,玩家蓝图一旦持有它,就获得了处理“拾取钥匙”这类特定消息的资格。
当希望不同的蓝图之间能互相通信,但又不希望它们产生直接依赖(即了解对方的内部细节)时,使用蓝图接口是理想的解决方案。
可请按照以下步骤,创建一个包含两个函数的蓝图接口:
打开内容浏览器,进入Content > AdventureGame > Designer > Core目录。
在Core文件夹的空白处右键点击,在菜单中选择蓝图(Blueprint),然后点击蓝图接口(Blueprint Interface)。 将该新资产命名为
BPI_PlayerKeys,然后双击打开。可以看到,这个窗口的布局与常规的蓝图编辑器非常相似。 在编辑器右侧,是我的蓝图(My Blueprint)面板,其中会列出该接口包含的所有函数。 该面板下方则是细节面板。
在我的蓝图面板中,可以看到系统已自动创建了一个新函数,并处于选中状态。 将此函数命名为
fnBPIAddKey。选中该函数,然后在细节面板中,找到输入(Inputs)栏,点击旁边的+按钮来添加一个新的输入参数。
将该输入参数命名为
KeyType,并将其类型设置为枚举键类型(Enum Key Type)。同样在细节面板里,找到类别(Category)字段,输入
Keys。 为函数设置类别后,在其他蓝图的接口列表中就能更容易地找到它。接下来,在“我的蓝图”面板中添加第二个函数,命名为fnBPIGetKeys,它将负责返回玩家持有的钥匙。
选中这个新的fnBPIGetKeys函数,在细节面板中找到输出(Outputs)栏,点击+按钮添加一个名为Held Keys的输出参数。
将其类型设为枚举键类型,并将容器类型设为数组(Array),这样它就能返回玩家持有的所有钥匙。
保存并编译接口。 完成后,即可关闭BPI_PlayerKeys的编辑器窗口。
接口与蓝图系统紧密相关,因此和普通蓝图一样,在修改后也需要编译才能生效。
值得注意的是,在蓝图接口中,我们只定义了函数的“声明”(即函数名、输入和输出)。 接口函数本身并不包含任何逻辑,但其结构(特别是输入和输出的定义)决定了它们在其他蓝图中的具体用法。
具体来说,没有输出的接口函数(如fnBPIAddKeys)通常作为事件来使用。而带有输出的函数(如fnBPIGetKeys),则可以像常规函数一样在实现它的蓝图中添加逻辑。
创建新的玩家角色
在为角色添加新功能前,我们先不直接修改默认角色,而是通过复制它来创建一个自定义的变体版本。 同时,还需要更改游戏模式(Game Mode)的设置,以便在游戏中使用这个新角色。
请按照以下步骤,为项目创建专属的玩家角色:
打开内容浏览器,进入Content > AdventureGame > Designer > Blueprints文件夹。
首先,创建一个名为
Characters的新文件夹。接着,在内容浏览器中进入Content > Variant_Shooter > Blueprints > FirstPerson文件夹。
将
BP_ShooterChracter资产拖动到刚才创建的Characters文件夹中,在弹出的菜单中选择复制到此处(Copy Here)。在Characters文件夹中,右键点击新复制的资产,将其重命名为
BP_AdventureCharacter。前往编辑(Edit)> 项目设置(Project Settings)。 在编辑器左侧面板中,打开项目 > 地图和模式(Project > Maps & Modes) 设置。
在DefaultGameMode(默认游戏模式)设置下,展开SelectedGameMode(所选游戏模式)的选项。
游戏模式(Game Mode)是一种定义游戏世界规则的资产,其中一项重要规则就是指定默认的玩家角色。 现在需要修改该设置,让游戏使用我们新创建的角色。 游戏模式的设置既可以在这里直接修改,也可以通过打开其资产文件进行编辑。
将默认Pawn类(Default Pawn Class)选项更改为
BP_AdventureCharacter。完成后,关闭项目设置(Project Settings)窗口。
为玩家添加蓝图接口
本节将对玩家角色蓝图进行修改。 这个角色蓝图本身已经预设了许多实用的函数和接口,我们要做的是为其添加之前创建的BPI_PlayerKeys接口,从而赋予它拾取钥匙的能力。
接下来,将修改BP_AdventureCharacter蓝图,为其添加钥匙相关的功能。
请按照以下步骤,为角色添加蓝图接口函数:
在内容浏览器中,定位到Characters文件夹并打开
BP_AdventureCharacter。首先需要添加BPI Player Keys接口,以确保该玩家蓝图能够实现此接口。 在蓝图编辑器顶部的工具栏中,点击类设置(Class Settings)按钮。
在编辑器右侧的细节面板中,找到接口 > 已实现接口(Interfaces > Implemented Interfaces)栏,点击添加(Add)按钮,然后从下拉列表中选择
BPI_PlayerKeys。 此操作将使该角色蓝图能够实现fnBPIGetKeys和fnBPIAddKey这两个接口函数。编译该蓝图,使接口函数的改动生效。 编译后,在我的蓝图面板的“接口”(Interfaces)区域,可以看到新增了一个Keys类别,其中包含了fnBPIAddKey和fnBPIGetKey两个函数。 其中一个函数的图标是黄色的,这表示它在当前蓝图中将作为事件来使用。
存储已拾取的钥匙
玩家需要一个变量来存储已收集的钥匙。 考虑到玩家可能同时持有多把钥匙,这个变量应设为数组类型。
请按照以下步骤,创建一个用于存储玩家钥匙的数组变量:
在
BP_AdventureCharacter蓝图中,于我的蓝图面板的变量列表处添加一个新变量。将该变量命名为
Held Keys。选中该变量,然后在细节面板中,将容器类型设置为数组,并将元素类型设置为枚举钥匙类型。 必须使用数组,因为玩家需要能够同时持有多把钥匙。
请按照以下步骤,实现在玩家拾取钥匙时将该钥匙添加到Held Keys数组的逻辑:
切换到角色蓝图的事件图表(Event Graph)选项卡。
在图表的空白处右键点击,搜索并添加事件fnBPIAddKey。 当fnBPIAddKey接口消息被调用时,就会触发这个事件节点的执行。
从该事件节点的执行引脚拖出连线,搜索并添加一个
数组添加(Array Add)节点,即Add节点。 该节点的功能是向一个数组中添加一个新元素。将Held Keys变量从“我的蓝图”面板拖入事件图表,并选择Get来创建一个该变量的“Get”节点。
将Held Keys节点的输出引脚连接到数组添加节点的目标数组(Target Array)输入引脚。 该引脚的图标是一个正方形。
将事件节点的Key Type引脚与Add节点的新物品(New Item)输入引脚连接。
这样,每当该事件函数触发时,玩家角色就会将对应的Key Type添加至其“ Held Keys”数组。
检索玩家持有的钥匙列表
教程的下一部分将要制作的门需要检查玩家持有的所有钥匙,因此玩家蓝图需要具备一个功能,用以返回其已拾取的钥匙数组。
请按照以下步骤,处理钥匙的获取逻辑:
在
BP_AdventureCharacter蓝图中,找到并展开我的蓝图(My Blueprint) > 接口(Interfaces)下的Keys分类。可以看到,列表中的fnBPIGetKeys函数图标为灰色,这表明它可作为常规函数(而非事件)来使用。
双击fnBPIGetKeys函数,打开其对应的图表。
将Held Keys变量拖入图表,并选择获取(Get),创建一个该变量的引用节点。
将Get Held Keys节点与返回(Return)节点的Held Keys引脚连接。
此时,fnBPIGetKeys函数的图表应与下图一致:
实现钥匙与玩家的碰撞检测
接下来要添加一项功能,使得玩家拾取钥匙时能够触发fnBPIGetKeys事件函数。 该功能的触发时机是玩家的碰撞体与钥匙的碰撞体积发生接触时。
具体而言,需要为钥匙的胶囊体(Capsule)碰撞组件添加一个事件。 所谓事件,即指在Gameplay过程中,因某种情况发生而被触发的逻辑。 在本例中,当玩家Actor与钥匙的胶囊体发生重叠,钥匙便会执行一系列预设的动作。
请按照以下步骤,添加重叠事件并验证与之重叠的Actor是否为玩家:
打开
BP_Key蓝图,在事件图表(EventGraph)中找一个空白位置。在组件(Components)面板中,右键点击胶囊体组件,选择添加事件 > 添加OnComponentBeginOverlap(Add Event > Add OnComponentBeginOverlap)。 相应的事件节点便会出现在事件图表中。 一旦该组件与另一个Actor发生重叠,此事件节点就会被触发。
事件节点本身会提供与该事件相关的信息。 例如,触发重叠的Actor对象会通过其他Actor(Other Actor)引脚输出。
从变量(Variables)列表中拖出OtherActor变量,并选择设置(Set)。 设置(Set)节点的作用是将一个新值存入指定的变量。
将事件OnComponentBeginOverlap节点的执行(Exec)引脚与设置其他Actor(Set Other Actor)节点的执行(Exec)输入引脚连接。
将事件OnComponentBeginOverlap节点的其他Actor引脚与设置其他Actor节点的其他Actor输入引脚连接。
在执行钥匙的后续逻辑前,必须先检查与之重叠的Actor是否为玩家,因为设定上只有玩家才能拾取钥匙。 判断方法是,检查该Actor是否实现了指定的蓝图接口。
在设置(Set)节点附近右键点击,添加一个对象是否实现接口(Does Object Implement Interface)节点。
在对象是否实现接口节点上,将接口(Interface)引脚的值设为BPI_PlayerKeys。
将设置其他Actor节点的蓝色输出引脚与测试对象(Test Object)输入引脚连接。 该引脚的功能等同于一个获取其他Actor(Get Other Actor)节点。
从对象是否实现接口节点的返回值(Return Value)引脚拖出,并添加一个分支(Branch)节点。
连接设置(Set)节点的执行输出与分支节点的执行(Exec)输入引脚。
分支(Branch)节点用于检查一个条件的真伪,并根据结果执行不同的逻辑分支。 在此,将基于重叠的Actor是否为玩家这一判断,分别为True、False两种结果创建不同的处理逻辑。
请按照以下步骤,实现在玩家触碰钥匙时调用“添加钥匙”的功能:
如果Branch节点的结果为True,说明该Actor能够拾取钥匙,此时应触发接口中的事件函数。 从分支节点的True引脚拖出,添加一个Fn BPIAdd Key (Message)节点。
此处添加的是消息节点而非普通函数节点,其原因在于,调用蓝图接口函数本质上是发送一条消息。 只有实现了该接口的目标(Target)蓝图才会对这条消息作出响应。
将Fn BPIAdd Key节点的目标(Target)引脚与一个新建的获取其他Actor节点连接。
将Key Type引脚与一个新建的获取钥匙类型(Get Key Type)节点连接。 这也是一种添加变量引用节点的快捷方法。
钥匙被拾取后,为了防止重复拾取,它应该在短暂延迟后从场景中消失。 为此,从Fn BPIAdd Key节点的执行(Exec)引脚拖出,添加一个延迟(Delay)节点。 其持续时间(Duration)参数保持默认值
0.2即可。计时结束后,钥匙便应消失。因此,连接一个销毁Actor(Destroy Actor)节点至延迟节点的已完成(Completed)引脚。 确保该节点的目标(Target)参数为self,这表示让钥匙Actor将自身从关卡中移除。
保存并编译蓝图。
此时可以看到,分支节点的False引脚并未连接任何后续节点。 这样做的原因是,如果重叠的Actor未实现钥匙接口,它便无法拾取钥匙,所以不需要执行任何操作。
完成后,钥匙的事件图表整体逻辑应与下图一致:
这里又出现了本页开头的资产图,但这次显示的是你创建的所有资产和功能的摘要,以及它们如何组合在一起,共同实现钥匙的外观与行为:
测试最终的钥匙功能
回到关卡编辑器,将每种颜色的钥匙各放置一个到场景中。 现在可以进入游戏,通过控制角色走过钥匙来尝试拾取。
从内容浏览器拖入钥匙后,按End键可使其吸附到正下方的地面上。 该快捷键的作用是将选中的关卡物体对齐到其下方的表面。
下一步
在下一节中,将修改门蓝图,使其能够像钥匙一样改变颜色,并且只有当玩家持有相应钥匙时,门才会保持开启。