视觉脚本教程(逻辑方块)
第一步:基本玩家移动
Lesson 3 of 10 • 20 XP
Keep your place in this quest
Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.
在本课中,我们将继续开发我们 Player 的基本移动逻辑。
使用 Cave Engine 的 Logic Bricks,我们将创建负责让角色行走和奔跑的逻辑。在这个过程中,您将学习如何捕获玩家输入,将输入转换为移动方向,控制移动速度,并保持视觉逻辑的组织。
本课构建在之前创建的跳跃逻辑之上。现在,我们不仅仅对单个按键进行反应,而是同时读取多个按键,并使用它们来定义 Player 应该移动的方向。
1. 添加 Sequence
为了继续开发我们 Player 的移动逻辑,我们将学习如何使用 Sequence 节点。
Sequence 节点让您可以从单个输入创建多个 Flow 输出。这是有用的,因为许多游戏系统需要从同一事件运行多个逻辑片段。
例如,我们的 On Update 事件需要每帧检查跳跃逻辑,但它也需要每帧检查移动逻辑。与其将所有内容放在一个大的混乱链中,我们可以使用 Sequence 将流程分成多个组织良好的分支。
这样,同一个 On Update 事件每帧可以以更清晰和更可控的方式执行不同的逻辑块。

2. 创建移动逻辑
为了创建 Player 的移动,我们将首先添加 Events 节点,然后添加 Active 节点。
Active 节点检查一个键是否当前被按下。这与检查一个键是否仅被按了一次是不同的。对于移动,我们通常想知道玩家是否持续按下该键,因为角色应该在该键保持激活时继续移动。
我们将对所有移动键进行此操作:
- W 向前移动
- S 向后移动
- A 向左移动
- D 向右移动
Active 节点的输出是一个 Bool 值。布尔变量只能有两种状态:True 或 False。
当我们使用 Bool To Float 节点将该布尔值转换为 Float 时,我们得到:
- 当值为 True 时,输出为 1
- 当值为 False 时,输出为 0
这使我们能够在数学运算中使用键盘状态。
例如,我们可以将 S 的值减去 W 的值,以计算前后的移动。我们还可以将 A 的值减去 D 的值,以计算左右的移动。
这是有效的,因为每个键返回的值要么是 0 要么是 1。
例如,对于前后的移动:
- 如果按下 W 而未按下 S,结果为
1 - 0 = 1,因此 Player 向前移动。 - 如果按下 S 而未按下 W,结果为
0 - 1 = -1,因此 Player 向后移动。 - 如果两个键都未按下,结果为
0 - 0 = 0,因此该轴没有移动。 - 如果两个键都按下,结果为
1 - 1 = 0,因此它们互相抵消。
通过这些结果,我们添加一个 Make Vector 3 节点,并将计算出的值连接到 X 和 Z 轴,负责定义移动方向。
现在将 Sequence 节点的第一个 Then 输出连接到此移动逻辑的流程,而另一个 Then 输出可以继续用于在之前的课程中创建的跳跃逻辑。
最后,获取 Entity,访问其 Character Component,并使用 Set Walk Direction 节点。将 Make Vector 3 创建的向量连接到方向参数,以便 Character Component 知道 Player 应该移动的方向。

现在我们需要创建一个限制器来控制 Player 的移动速度。
而不是直接在 Set Walk Direction 中定义移动方向,我们将首先将移动方向存储在一个属性中。这给了我们更多的控制,因为我们将能够在将其应用于角色之前修改这个方向。
打开 Properties 选项卡,创建一个新属性,将其类型更改为 Vector3,并将其重命名为 Move Dir。
这个属性将用于存储 Player 的移动方向,并将作为下一步逻辑调整的基础。


单击属性旁边显示的齿轮图标,选择 Change Type 来更改其类型。
然后选择 Vector3。


现在回到您的 Logic Bricks 图表中,设置刚刚创建的 Move Dir 属性。

将 Make Vector 3 节点的输出连接到 Move Dir 属性的值。
这意味着,我们不是将移动方向直接应用于角色,而是将该向量存储在一个属性中,以便我们可以在后续逻辑部分使用和修改它。

现在我们将角色的移动方向存储在 Move Dir 属性中,让我们再创建两个 Float 类型的属性:
- Walk Speed
- Run Speed
这些属性将定义 Player 在每个移动状态中的速度。
在这里使用属性是一个好习惯,因为它使得将来调整移动更容易。您可以直接从 Properties 选项卡中选择 Entity,并调整行走和奔跑速度,而不必在图表中搜索硬编码值。

现在再创建一个属性,这一次是 Bool 类型,叫做 Is Running。
这个属性将存储角色的奔跑状态。它将告诉逻辑玩家当前是否在奔跑,从而使我们能够在 Walk Speed 和 Run Speed 值之间做出选择。

现在添加一个 Active 节点来检查 Shift 键是否被按下。
然后使用 Set Is Running 根据该条件定义属性。当 Shift 处于激活状态时,Is Running 应该设置为 True,表示角色正在奔跑。

现在我们将使用存储在 Move Dir 属性中的方向来定义 Walk Direction,同时还应用每个移动状态的正确速度。
为此,添加一个 If 节点,检查 Is Running 属性是 True 还是 False。
如果结果为 True,获取 Move Dir 的值并将其乘以 Run Speed 属性。
如果结果为 False,获取 Move Dir 的值并将其乘以 Walk Speed 属性。
最后,将此乘法的结果连接到 Set Walk Direction 节点。
这样,移动方向保持不变,但其强度根据玩家是行走还是奔跑而变化。

现在我们需要解决一个小问题。
如果您斜着移动角色,您可能会注意到它的移动速度快于仅向前、向后、向左或向右行走。这是因为组合两个移动轴会产生一个更大幅度的向量。
例如,仅向前移动会产生一个方向:
(0, 0, 1)
但同时向前和向右移动会产生类似这样的向量:
(1, 0, 1)
这个对角线向量的长度比单轴向量大,导致角色以对角线的方式移动得更快。
为了修复这种行为,我们将在将其存储在 Move Dir 属性之前,对方向向量进行归一化处理。
首先获取 Make Vector 3 生成的向量的 Length。
然后添加一个 If 节点检查这个值是否大于 0。
这个验证很重要,因为我们不应该对空向量进行归一化。长度为 0 的向量意味着没有按下任何移动键,因此没有方向可供归一化。
如果条件为真,使用 Normalized 节点获取向量的归一化版本。
否则,使用原始向量。
最后,将结果连接到 Move Dir 的 Set Property 节点。
这保留了移动方向,但保持其幅度一致,确保角色在每个方向以相同的速度移动。

3. 使用 Events
在 Logic Bricks 中,有更有组织的方式来构建逻辑流。
除了评论和 Sequence 节点外,我们还可以使用 Events 使系统更清晰,易于理解。
Events 允许您分离特定的逻辑块,并从图表中的其他位置调用它。这在您的图表增长时尤其有用,因为它可以避免将所有内容直接连接到 On Update 的一个大链中。
现在让我们创建一个新事件,名为 Move Player。

然后将该事件连接到 Player 移动逻辑块的流程中。

通过这种方式,我们可以将整个移动逻辑放在 On Update 的调用中,而不是直接连接。这使得流程更清晰,更模块化,易于理解,尤其是在项目逻辑变得更加复杂时。

在这一点上,Player 已经使用 Logic Bricks 创建了基本的移动系统。
逻辑现在检查移动键,计算移动方向,对方向进行规范化以避免更快的对角线移动,将其存储在 Move Dir 属性中,检查玩家是否在奔跑,应用正确的速度,并最终通过 Set Walk Direction 将结果发送到 Character Component。