Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

在本课程中,我们将通过创建连接到平台逻辑的按钮来完成上一课中开始的系统,并完成这两个系统之间的交互。

在此过程中,我们将探索 Cave 的视觉逻辑系统中的几个重要概念。您将学习如何使用 Rigid Body 检测碰撞,使用 Delay 节点控制时间上的动作,改变游戏中的实体颜色,并练习创建和使用 functions 以保持逻辑积木的组织和可重用性。

到本课程结束时,我们将拥有一个完整的系统,按钮可以由玩家激活并正确地与之前创建的平台通信。

1. 创建按钮

首先创建一个新的 Entity Template

然后根据其用途重命名实体,配置将用作其视觉表现的 Mesh,并添加必要的物理组件,以便它能够在游戏中正确交互。

之后,创建一个新的 Logic Brick 并将其链接到按钮实体。

这个过程与我们之前创建平台时的操作非常相似,因此这也是一个很好地练习您已经学过的概念的机会。

在此步骤结束时,我们将拥有按钮的基本结构,准备接收激活逻辑。

image.png

现在,有一个非常重要的步骤:我们不能忘记给按钮实体添加 button 标签。

如果您还记得,在上一课中,我们已经准备好平台逻辑,以便自动计算场景中按钮的数量,使用的就是这个标签。

因此,该标签需要创建并使用在平台逻辑中使用的相同名称分配给按钮。

如果标签名称不同,即使是小细节,平台也无法正确找到按钮,计数也不会按预期工作。

在继续之前,请确保您创建了 button 标签并将其添加到按钮实体上。

image.png

现在我们也给按钮实体添加一个属性。

我们使用 button 标签在地图中识别按钮,但我们将使用一个属性来控制其行为的一部分。

创建一个新的属性,称为 Active Time,类型为 Float

该属性将存储按钮应保持激活的时间,然后自动返回到非激活状态。

这使系统更灵活,因为每个按钮可以有不同的激活时间。例如,一个按钮可以保持激活 3 秒,而另一个按钮可以保持激活 10 秒,而不需要更改 Logic Brick 本身。

image.png

2. 创建按钮逻辑

现在我们的实体已准备就绪,标签和属性已配置,让我们开始创建按钮行为。

第一步是检测按钮实体与玩家之间的碰撞,以便我们可以在玩家接触时激活它。

然而,在实现此逻辑之前,我们需要考虑一个重要的细节:我们只希望在按钮当前处于非激活状态时才能激活它。

由于按钮将具有两种不同的状态,activeinactive,我们需要一种方法来存储当前使用的状态。

为此,在按钮 Logic Brick 中创建一个名为 Active Button 的新属性,类型为 Boolean

该属性将存储按钮的当前状态,指示它是否处于激活状态。我们将在接下来的步骤中使用此值来控制按钮的整个行为。

image.png

现在我们可以开始构建视觉逻辑。

On Update 中,我们将不断检查按钮是激活还是非激活,使用刚刚创建的 Active Button 属性。

为此,获取其值使用 Get Active Button 并使用 If 节点检查其状态。

如果条件为 False,则表示按钮处于非激活状态,可以被激活。在这种情况下,我们将检测按钮与玩家之间的碰撞。

为此,添加一个 Collided With 节点。

此节点需要一个 Rigid Body Component,因此获取按钮 Entity,并从中获取在配置物理时添加的 Rigid Body Component

我们还需要告诉节点我们想要检测哪个对象。为此,给角色添加一个 player 标签,并将该标签传递给 Collided With

这样,只有当按钮与玩家碰撞时,此碰撞才会被视为有效。

通过这种结构,按钮只能在非激活状态且玩家实际与之碰撞时被激活。

image.png

现在我们已经定义了两个路径,首先实现按钮激活时的逻辑。

之后,我们将创建负责激活它的行为。

为此,遵循 If 节点的 True 条件,检查按钮是否激活。

在此流程中,我们将使用在按钮实体中创建的 Active Time 属性来控制按钮应保持激活的时间。

首先,获取按钮 Entity,并通过 Get Properties 节点访问其属性。

然后使用 Get Property,连接之前返回的字典并使用 Active Time 作为 Key

由于该属性是 Float,请将 Get Property 的输出类型更改为 Float,以确保我们可以在逻辑的下一部分正确使用该值。

image.png

现在,Get Property 的输出返回 Active Time 属性的值,定义按钮应该保持激活多长时间。

接下来,添加一个 Delay 节点,并使用该值作为持续时间。

这样,等待时间由实体属性直接控制,使得不同按钮可以有不同的激活时间,而无需更改逻辑。

Delay 完成后,使用 Set Active Button 并将其值设置为 False

这样,按钮会在其属性中指定的时间后自动返回到非激活状态。

image.png

很好。现在让我们遵循其他路径,创建负责激活按钮的行为。

Collided With 节点的输出返回一个 Bool 值。

当该值为 True 时,表示按钮与玩家发生了碰撞。

此时,我们可以简单地使用 Set Active Button 并将其值设置为 True

这样,按钮进入激活状态,并自动开始使用我们之前创建的激活逻辑,保持激活一段时间,然后再次禁用。

通过这样,我们创建了一个完整的行为循环:

  • 当玩家与按钮碰撞时,它被激活
  • Active Time 中定义的时间之后,被禁用
  • 之后,可以通过另一次碰撞再次激活

虽然这个逻辑很简单,但它已经赋予按钮两种不同的状态,并将成为我们接下来要添加的功能的基础。

image.png

一切正常,但还有一个重要的部分。

尽管按钮激活和停用逻辑已正确工作,但我们的平台仍然不知道何时激活了按钮。

这正是我们在 Scene 中先前创建的 Button Count 属性变得重要的地方。

如果您记得,我们在平台逻辑中定义了,当此属性的值等于地图中按钮的总数时,平台应该被移除。

换句话说,平台已经准备好react,但到目前为止,没有按钮改变这个值。

现在我们需要做的是允许按钮在激活和停用时直接修改场景的 Button Count 属性。

这是练习 Cave 中另一个非常重要的逻辑积木特性的好机会:创建 functions

而不是多次重复相同的逻辑,我们将把这个行为封装到可重用的函数中,使我们的图形更为有序,更易于理解和维护。

由于 Button Count 属性存储在场景中,因此我们首先需要访问它。

为此,使用 Get Scene 来获取场景,然后使用 Get Properties

image.png

3. 创建控制场景属性的函数

从这些节点,我们将创建一个函数。

为此,选择涉及的节点,右键单击,并选择 Promote Selection to Function

image.png

然后将新函数重命名为一个清晰且具有描述性的名称,代表它在项目逻辑中的作用。

在这种情况下,我们将使用名称 Set Scene Property

image.png

现在让我们结构化 Set Scene Property 函数的工作方式。

首先,将 Scene 属性字典传递给 Get Property 节点。这个字典来自 Get Scene → Get Properties 的流程。

然后将 Get Property 的输出更改为 Int,确保我们正在处理整数值。

Function Inputs 中,为该函数创建两个新参数:

  • Prop Name,类型为 String
  • Value,类型为 Int

Prop Name参数将用作Key,在Get Property中,让函数能够访问场景属性字典中的所需属性。

然后我们将使用Set Property更新这个属性。

为此,获取属性的当前值,将Value输入添加到当前值,并将结果写回同一属性。

我们再次传递场景属性字典,并使用Prop Name作为键。

这创建了一个通用且可重用的函数,可以以简单和有组织的方式修改场景属性。

该函数不仅设置确切的值,而像一个增量系统:它将收到的Value添加到场景属性的当前值上。

image.png

有了这个函数,我们不再需要在主图形中保留整个节点链。

现在,在将Active Button设置为True之后,我们只需调用该函数。

这意味着在按钮激活的瞬间,我们立即告诉平台逻辑又有一个按钮被按下。

为此,传递属性名称Button Count,这是存储在场景中的属性,并将值1作为增量。

该函数将自动将当前属性的值加+1

通过这种方式,任何激活的按钮都直接更新系统的全局进度,而无需重复逻辑。

这还为我们在未来重用此函数更改场景属性提供了更多灵活性。

image.png

为了展示这是多么简单和灵活,让我们回到激活按钮的逻辑。

激活时间结束后,我们将Active Button设置为False,再次调用Set Scene Property

Prop Name参数将是Button Count,使用相同的场景属性。

但这次,Value参数将是-1

由于我们的函数将接收到的值添加到当前场景属性值,将负数传递会自动将当前Button Count减去1。

image.png

这样,每当一个按钮被禁用时,系统也会正确更新全局进度,使平台逻辑与地图中按钮的真实状态保持同步。

image.png

现在我们的逻辑如预期般工作。

还有一个重要细节:创建一个视觉效果,清晰地告诉玩家按钮何时处于激活状态。

每当按钮被激活时,我们将直接使用Tint改变它的颜色,视觉上突出它的状态。

在将Active Button设置为True之前,添加一个Sequence

由于我们不再需要三个流,我们可以通过右键单击并选择Remove Last Flow Output来删除其中一个输出,只保留两个路径。

然后获取按钮的子实体ButtonMesh,访问其Mesh Component,并调整Tint值。

Y轴上,将值设置为25,使按钮在激活时显现绿色。

这为玩家提供了明确的视觉反馈,每当按钮被按下时,提高了游戏内交互的可读性和响应性。

image.png

同样,当按钮变为非活动状态时,我们将恢复按钮的原始颜色。

使用相同的逻辑,但在我们将Active Button设置为False的流中。

此时,再次访问子实体ButtonMesh,获取其Mesh Component,并调整Tint值。

要恢复默认颜色,只需将所有Tint值设置为1,恢复按钮的原始视觉状态。

通过这种方式,每当按钮被禁用,它也会返回到初始外观,使玩家明确知道它可以再次激活。

image.png

通过选择我们添加到场景中的button template instance,我们可以访问它的属性并更改Active Time的值。

这样,每个按钮都可以有不同的激活时间并独立工作。

这为我们在关卡内创建多样化挑战提供了更大的灵活性,因为每个按钮都可以单独配置,而不改变系统的主逻辑。

image.png

通过这一点,我们可以在地图上添加任意多的按钮,每个按钮都有不同的激活时间和独立行为。

平台会自动遵循此设置,而不需要手动调整,因为计数是在运行时进行的。

系统也与游戏的真实状态保持同步。按钮被激活和禁用时,全局值更新,平台在条件满足时响应,并在正确的时候从场景中移除。

除了逻辑,我们还为玩家添加了重要的视觉反馈。

当按钮被激活并在被禁用时恢复其原始外观,使系统变得更加清晰和直观。玩家可以直观地理解哪些按钮是活动的,哪些还需要注意。

最终,我们创建了一个模块化和可扩展的系统,结合了实体之间的通信,通过场景的集中控制,以及在游戏世界的直接视觉反馈。

这个结构可以轻松扩展用于门、平台、电梯、谜题、陷阱、定时挑战和许多其他交互事件。

image.png