第 3 章:发射子弹并击败敌人
第 3 章的目标
在第 2 章中,我们实现了以下目标:
- 创建一个简单的舞台,玩家角色可以在其中行走和跳跃。
在本章中,我们将进一步深入,讲解如何实现:
以下是第 3 章完成后的效果示例:
规划“玩家射击以击败敌人”的实现步骤
让我们思考所需的步骤。
-
玩家需要一个新的射击状态。
-
为了发射子弹,我们还需要创建一个新的子弹对象。
-
由于我们还没有敌人,因此还需要创建一个敌人对象。
因此,在第 3 章中,我们的目标将是:
-
创建子弹对象
-
为玩家添加射击状态
-
创建敌人对象
最后,为了实现击败敌人,我们需要实现造成伤害的过程(即攻击系统)。
ACTION GAME MAKER 提供了专门用于处理攻击和伤害的系统,因此在开始制作之前,让我们花些时间了解该系统的工作原理。
“攻击”与“伤害”在 ACTION GAME MAKER 中
攻击命中
您是否还记得 Player 对象内部的 HitArea2D / HitCollision 和 AttackArea2D / AttackCollision 节点?
在 ACTION GAME MAKER 中,每当来自 AttackArea2D 的 AttackCollision 与来自 HitArea2D 的 HitCollision 发生碰撞时,系统会自动处理伤害。
此外,借助 Godot 内置的 CollisionLayer(碰撞层)和 CollisionMask(碰撞掩码)功能,您可以精细调整哪些对象会“碰撞”,哪些不会。
CollisionLayer 与 CollisionMask
如前文在“墙壁碰撞”中所解释的,Godot 通过 CollisionLayer 和 CollisionMask 系统来控制碰撞。
可以将它们理解为为碰撞检测增加深度的层级。
您可以在如下面板中进行配置:
- Layer(层) → “该对象存在于哪一层”
- Mask(掩码) → “该对象可以与哪些层发生碰撞”
例如:
- 如果 AttackCollision 的掩码设置为层 1 和 2,则它无法命中仅存在于层 3 上的 HitCollision。
此设置还有助于避免不必要的情况,例如角色与其自身的攻击命中框发生碰撞。
伤害处理
当攻击成功命中时,伤害会自动处理:
-
攻击对象的攻击力(在 BaseSettings 中设置)会从防御对象的 HP 中扣除。
-
之后,您可以启用 Invincibility(无敌状态,同样在 BaseSettings 中设置),使受损对象在一段时间内免疫后续攻击。
通过此系统,ACTION GAME MAKER 自动处理攻击与伤害逻辑的核心部分,您只需配置相关的节点和设置即可。
创建子弹对象
既然我们已经了解了攻击的基本原理,现在让我们实际创建一个子弹。
子弹也将是一个游戏对象,因此基本工作流程与玩家相同:
-
分配一张图片
-
调整移动速度等设置
-
使用可视化脚本添加处理逻辑
唯一的区别是,子弹不直接由玩家的输入设备控制。
相反,子弹通过“射击子弹”动作发射并赋予移动,因此我们不需要为子弹本身创建自定义移动逻辑。
为子弹创建游戏对象
-
打开一个新场景标签页,并将根节点选择为游戏对象。
-
在创建新对象窗口中,设置:
-
对象名称:bullet
-
模板:bullets
-
类型:bullet_base
-
子弹对象模板将被加载。
设置子弹图片
让我们为子弹分配一张图片。
我们也可以创建动画让子弹看起来更酷,但为了本教程,我们将保持简单,仅使用静态图片。
-
右键点击下方的图片并将其保存到计算机。

-
将下载的 bullet.png 拖放到编辑器中的文件系统里。
-
在场景面板中,选择 Sprite2D。
- 在检查器中,将 bullet.png 拖放到 纹理 属性上(当前为
<empty>)。
调整子弹的 MoveAndJumpSettings
我们希望子弹的移动速度快于玩家。
玩家的速度设置为 300,因此我们将子弹速度设置为 600。
-
在场景面板中,选择 MoveAndJumpSettings 节点。
-
在检查器中,将 水平速度 和 垂直速度 均设置为 600。
现在我们已经拥有了一个带有独立精灵和速度设置的基本子弹对象。
调整子弹的攻击碰撞箱
在 AttackArea2D 中设置碰撞层和掩码
默认情况下,该对象位于 第 1 层,其 掩码 (Mask) 设置为 1 和 2。
这意味着它可以击中位于第 1 层和第 2 层的对象。
然而,玩家 (Player) 也位于第 1 层,掩码为 1 和 2。因此,如果保持现状,子弹一旦发射就会与玩家发生碰撞。
为了防止这种情况,我们将子弹的碰撞层移至 第 3 层,并将掩码仅设置为 3。
-
在 场景面板 (Scene panel) 中,选择 AttackArea2D。
-
在 检查器 (Inspector) 中,展开 碰撞 (Collision) 部分。
-
将出现一个用于选择 碰撞层/掩码 (Collision Layers/Masks) 的面板。
现在,子弹将不再与玩家发生碰撞。
调整 AttackCollision 的大小
目前,攻击碰撞箱比子弹精灵大得多。
让我们调整其大小,使其更好地匹配子弹。
-
在 场景面板 (Scene panel) 中,选择 AttackCollision。
-
在编辑器视口中,拖动形状周围的橙色手柄以调整大小。
至此,您的子弹碰撞已正确设置——它不会击中玩家,且其攻击碰撞箱现在已适配子弹的大小。
设置子弹脚本
墙壁碰撞体(CollisionShape2D)的大小已经合适,因此无需更改。
基本设置完成后,让我们为子弹创建脚本。
子弹应在以下情况消失:
为实现这一点,我们只需要两个状态:移动和消失。
让我们开始设置。
附加脚本
-
选择 子弹(GameObject) 节点。
-
在场景面板中,点击
+(附加脚本) 按钮。
-
保留默认选项并点击 创建,生成一个名为 bullet.vs 的新脚本。
设置“移动”状态
我们将默认状态 State001 复用作移动状态。
由于子弹的移动由“射击者”(发射它的对象)处理,因此该状态不需要额外的操作。
-
选择 State001。
-
在检查器中,将 标题 更改为 移动。
创建“消失”状态
-
在移动状态右侧右键点击并选择 添加状态。
-
选择新的 State001 并将 标题 重命名为 消失。
-
在检查器中,点击 + 添加可执行操作。
-
选择 RemoveSelf 并点击 添加。
链接 移动 → 消失
子弹应在以下情况消失:
我们可以使用 AND(与) / OR(或) 逻辑在单个链接中组合多个条件。
在本例中,我们将使用 OR 连接它们:
敌人碰撞 OR 瓦片碰撞 OR 摄像机外
步骤:
-
右键点击 移动 状态并选择 添加链接。
-
将链接连接到 消失 状态。
-
选择新链接,然后在检查器中点击 + 添加条件。
-
选择 ContactWithHitArea。
-
勾选 选择所有侧面 并点击 添加。
-
再次点击 + 添加条件。
-
这次选择 ContactWithTile。
-
选择 所有方向,对于逻辑条件,选择 OR,然后点击 添加。
-
使用 + 添加其他条件 添加第三个条件。
-
向下滚动并选择 Offscreen。
-
将 目标类型 设置为 此节点,将逻辑设置为 OR,然后点击 添加。
-
确认条件看起来正确。
- 如果 AND/OR 设置不正确,请点击图标进行切换。
注意:“ContactWithHitArea”应该使用 AND 吗?
AND/OR 设置指的是与 前一个条件 的关系。
由于这是 第一个条件,它是 AND 还是 OR 并不重要。
但如果您将其移动到其他条件下方,则会应用 AND。
为了安全起见,请将其保留为 OR。
子弹设置完成!别忘了 保存场景。
修改玩家对象以发射子弹
为了让玩家能够发射子弹,我们需要完成四个步骤:
A. 创建射击动画
B. 添加并配置 BulletsSettings 节点
C. 添加并配置 Connector 节点(射击点)
D. 在 Visual Script 中创建 “发射子弹”状态
让我们从第一步开始:添加射击动画。
A. 创建射击动画
首先,让我们思考一下玩家发射子弹的场景。由于我们要采用洛克人风格的设置,似乎需要三种射击状态:站立射击、移动中射击和空中射击。
然而,我们之前创建的“移动”动画设计为角色手持手臂向前奔跑,这非常适合射击动作。因此,我们只需要创建两个新动画:地面射击和空中射击。
我们将使用与之前相同的方法:所需的射击姿势已经存在于加载的精灵表中。工作流程是:添加动画 → 插入关键帧 → 加载到动画集。
创建“地面射击”和“空中射击”动画
-
将场景选项卡设置为“玩家”,并将编辑器视图设置为2D。
-
选择 AnimationPlayer 节点。
-
在底部的动画面板中,点击 Animation 并创建一个新动画。
-
将新动画命名为 Ground Shot。
-
选择 Sprite2D,并在检查器中展开 Animation 属性。
-
将 Frame 设置为 1(玩家站立并手持手臂向前的帧)。然后按下
+ (添加关键帧) 按钮。
-
在弹出窗口中,取消勾选 Create RESET Track,然后点击 Create。
-
重复步骤2–3以创建另一个新动画,这次命名为 Air Shot。
-
选中 Sprite2D,将 Frame 设置为 2(玩家处于空中并手持手臂向前的帧)。按下
+ (添加关键帧) 按钮插入关键帧。
在动画集中注册动画
-
选择 Player (GameObject) 节点。
-
在检查器中,点击 Bulk Load Animations 按钮。
-
Ground Shot 和 Air Shot 动画现在将被添加到动画集中。
C. 添加和配置连接器节点
连接器节点用于在使用视觉脚本时指定“位置”,例如发射子弹的起点或对象应生成的位置。在本例中,连接器将作为发射点,因此我们将其放置在射击动画中所示的手的尖端。
-
选择玩家 (GameObject) 节点。
-
点击左上角的+ (添加子节点) 按钮,打开创建新节点对话框。
-
选择连接器并点击创建。
-
选择AnimationPlayer 节点,并将动画切换为地面射击。
-
再次选择连接器节点。
-
将编辑器工具切换为移动模式。
-
拖动✛(连接器标记)到角色手的尖端。至此,连接器设置完成。
D. 添加射击状态
接下来,让我们添加发射子弹所需的状态。我们需要 地面射击 和 移动射击 状态,以及一个 空中射击 状态。
然而,空中射击需要一些特殊处理。如果我们简单地从 空中射击 状态转换回 跳跃 状态,跳跃动作会再次触发,导致玩家每次射击都跳得更高。为了避免这种情况,我们将把 跳跃 状态拆分为两个状态:跳跃 和 空中。
- 跳跃 状态将立即转换到 空中。
- 在 空中 状态时,如果玩家触碰到地面(下方的瓦片),他们将转换回 待机 状态。
- 空中射击 将返回到 空中,从而防止重复的跳跃动作。
让我们逐步构建这个过程。
创建地面射击和移动射击状态
-
切换到脚本选项卡。
-
在 待机 状态的左侧附近创建一个新状态。
-
将新状态 State001 重命名为 地面射击。
-
在 选择动画 中,分配 地面射击 动画集。
-
点击 + 添加执行动作。
-
选择 FireBullet 作为动作。
-
在 子弹数据 中,指定您之前创建的子弹对象。
-
点击 连接器 旁边的 分配 按钮。
-
在 选择节点 窗口中,选择您之前创建的 连接器。
-
确认子弹数据 = “bullet” 且连接器 = “Connector”,然后点击 添加。
-
对于 移动射击,复制 地面射击 状态:
-
右键点击 地面射击 并选择 复制。
-
右键点击 移动 状态的右侧附近并选择 粘贴状态。
-
将新状态重命名为 移动射击。
-
启用复选框 继续上一个动画。由于 移动射击 使用与 移动 相同的动画,此处无需更改动画。
链接 待机 ↔ 地面射击 和 移动 ↔ 移动射击
我们希望按下 攻击 按钮时,在 待机 或 移动 状态下转换到 地面射击 或 移动射击。0.3 秒后,它们应返回到 待机 或 移动。
-
右键点击 待机 并添加指向 地面射击 的链接。
-
在属性中,勾选 在输入时触发。
-
展开 输入操作列表 (数组[输入条件])。
-
点击 + 添加输入 以添加新条目。
-
点击 并选择 新建输入条件。
-
展开 输入条件 并设置 输入键 = 攻击。
-
右键点击该链接并选择 复制。
-
右键点击 移动 并选择 粘贴链接。
-
将其连接到 移动射击。
-
右键点击 地面射击,添加指向 待机 的链接。
-
在检查器中,点击 + 添加条件。
-
选择 经过时间 作为条件。
-
将持续时间从 1 秒更改为 0.3 秒。
-
右键点击此链接,选择 复制。
-
右键点击 移动射击,粘贴链接,并将其连接回 移动。
此时,地面射击状态已完成。
测试地面射击
-
点击右上角的 运行项目 (F5) 按钮。
-
如果配置正确,在 待机 或 移动 状态下按下 X 将发射子弹。
-
如果不起作用,请检查以下内容:
-
动画未播放 → 检查状态动画设置和 AnimationPlayer。
-
动画播放但没有子弹 → 检查 FireBullet 动作设置。
-
子弹出现但不移动或飞行方向错误 → 检查 BulletsSettings。
测试成功后请关闭。
将跳跃拆分为跳跃和空中状态
-
在 跳跃 状态的左侧创建一个新状态。
-
将 State001 重命名为 空中。
-
将其 动画 设置为 跳跃(用于空中视觉效果)。
-
右键点击 跳跃,添加指向 空中 的链接。
-
在检查器中,设置 切换条件 = 无条件(这意味着跳跃会立即切换到空中)。
-
剪切现有的 跳跃 → 待机 链接:选中它,右键点击,然后选择 剪切。
-
右键点击 空中 并 粘贴链接,然后将其连接到 待机。
-
这样,落地转换现在通过 空中 进行,而不是 跳跃。
-
测试播放以确认 跳跃 → 空中 → 落地 的流程正常工作。
创建空中射击并链接
由于 空中射击 的工作方式与 地面射击 相同,只是使用了不同的动画,我们将重用现有状态。
-
右键点击 地面射击 并选择 复制。
-
将其粘贴到 空中 状态的左侧。
-
将 地面射击 (1) 重命名为 空中射击。
-
在检查器中,将 动画 更改为 空中射击。
-
复制 待机 → 地面射击 链接。
-
右键点击 空中,粘贴链接,并将其连接到 空中射击。
-
复制 地面射击 → 待机 链接。
-
右键点击 空中射击,粘贴链接,并将其连接到 空中。
最终测试
再次运行项目:
- 在 待机 或 移动 状态下按下 X → 玩家发射子弹。
- 按下 Z 跳跃,然后按下 X → 玩家在空中发射子弹。
如果两者都正常工作,您的射击系统已完成!
创建敌人对象
接下来,让我们创建敌人对象。我们将从最简单的敌人类型开始——它只进行左右移动。创建过程与创建玩家角色时相同:创建场景,分配图像和动画,配置节点,然后构建脚本。
创建 enemy 游戏对象
-
将编辑器视图从 脚本 切换回 2D。
-
创建一个新的场景标签,并将根节点选择为 游戏对象。
-
在 创建新对象 窗口中,设置以下内容:
-
对象名称:enemy
-
模板:角色
-
类型:2D 精灵角色基础
-
对象组:敌人
-
右键点击 未保存,并将场景保存为 enemy.tscn。
1 个赞
设置敌人的图像和动画
对于敌人,我们将使用下面提供的图像。与简单的对称圆形子弹不同,这个敌人是不对称的,并且需要根据其移动方向进行翻转。由于自动翻转功能通过动画集(Animation Set)处理,我们将使用 Sprite2D 设置纹理,使用 AnimationPlayer 创建动画,然后在敌人(GameObject)节点上配置 Animation Set,就像我们为角色所做的那样。
配置 Sprite2D
-
右键点击上面的图像并将其保存到您的 PC。

-
将图像拖放到 文件系统(FileSystem)中以导入它。
-
选择 Sprite2D 节点。
-
在检查器(Inspector)中,将 enemy.png 拖放到 纹理(Texture)属性中。由于此图像不需要分割成帧,精灵设置已完成。
使用 CollisionShape2D 调整碰撞形状
当前的碰撞形状比精灵小得多,因此我们需要调整它的大小。
-
在 场景(Scene)窗口中,选择 CollisionShape2D 节点。
-
拖动碰撞框角落处的橙色手柄以调整其大小,使其与精灵正确匹配。
配置 AnimationPlayer 并创建动画集
要设置动画集,我们需要一个动画。与角色不同,这个敌人不需要切换帧,因此只需创建一个动画即可。
-
选择 AnimationPlayer 节点。
-
在底部的动画窗口中,点击 动画(Animation),然后选择 新建(New)。
-
将新动画命名为 Move 并创建它。由于不需要轨道,此动画已完成。现在让我们设置动画集。
-
选择 enemy (GameObject) 节点。
-
在检查器中,点击 AnimationPlayer。
-
确认已分配正确的 AnimationPlayer,然后点击 确定(OK)。
-
点击检查器中的 批量加载动画(Bulk Load Animations)按钮。
-
展开动画集,确认 Move 已正确注册。
调整敌人的 BaseSettings
为了确保敌人能够被攻击击败,我们需要配置其生命值和无敌设置。
设置生命值
-
选择 BaseSettings 节点。
-
在检查器(Inspector)中,将 HP 和 Max HP 的值从 1 改为 3。
- 这意味着敌人在受到 3 点伤害后,生命值将降至 0。
设置无敌时间
无敌时间(Invincibility)可防止物体在受到伤害后的短时间内失去生命值。如果没有此设置,敌人可能会在同一瞬间受到多次伤害。
由于玩家的射击间隔设置为 0.3 秒,将无敌时间设置为约 0.2 秒 效果较好。
此外,无敌系统包含一个功能,可使物体在无敌状态下闪烁。若无敌时间为 0.2 秒,将闪烁间隔设置为 0.1 秒 即可让闪烁效果可见。
-
在检查器中,将 Invinciblity Duration(无敌持续时间)属性从 1.0 改为 0.2。
-
在其正下方,将 Blink Duration(闪烁持续时间)属性从 1.0 改为 0.1。
调整敌人的碰撞箱
接下来,让我们配置敌人的碰撞箱。由于我们将子弹对象的碰撞层设置为3,敌人也需要位于第3层,以便能与子弹正确交互。
在 HitArea2D 中配置碰撞层和掩码
-
选中 HitArea2D 节点。
-
在检查器(Inspector)中,展开 Collision 部分。
-
将 Layer 和 Mask 都更改为 3。
- 这确保了敌人的碰撞箱能够与子弹的攻击碰撞正确交互。
调整 HitCollision 的大小
目前,HitCollision 太大,因此我们需要调整其大小。
-
在 场景(Scene)窗口中,选中 HitCollision 节点。
-
拖动碰撞框的橙色角手柄来调整大小,使其略大于敌人的可见精灵。
调整敌人的攻击碰撞
接下来,让我们配置敌人的攻击碰撞箱。与子弹不同,攻击碰撞只需与玩家交互。由于玩家的碰撞层保持默认值,我们无需在此更改任何层或掩码设置。我们只需要调整碰撞形状的大小即可。
-
在场景窗口中,选择 AttackCollision 节点。
-
拖动碰撞框的橙色角手柄来调整其大小,使其与敌人的碰撞箱大小相匹配。
设置敌人脚本
敌人只会左右移动,因此我们只需要移动功能,以及当 HP 归零时使其消失的方法。
理论上,这可以通过三个状态实现——向左移动、向右移动和消失,但在这里我们可以利用**模板移动(Template Movement)**动作,它会自动处理简单的巡逻移动。
因此,我们将只创建两个状态:模板移动(Template Move)和消失(Vanish),并将它们链接起来,使得当 HP 归零时敌人消失。
附加视觉脚本
-
选择**敌人(GameObject)**节点。
-
点击**附加脚本(Attach Script)**按钮。
-
保持默认名称为 enemy.vs,然后按创建(Create)。
创建“模板移动”和“消失”状态
-
将 State001 重命名为 模板移动(Template Move)。
-
在检查器(Inspector)中,将**动画类别(Animation Category)**设置为 移动(Move)。
-
点击 + 添加可执行动作(Add Executable Action) 按钮。
-
选择 MovementTemplate。
-
将 移动时间(Move Time) 设置为 3,并启用 不能从边缘掉落(Can’t Fall Off Ledges)。
-
点击 添加(Add)。
-
在模板移动状态右侧的空白处右键单击,选择 添加状态(Add State)。
-
将新的 State001 重命名为 消失(Vanish)。
-
点击 + 添加可执行动作(Add Executable Action) 按钮。
-
选择 RemoveSelf 并添加它。
如果看起来像下图,则您的状态设置已完成。
链接模板移动到消失
-
右键单击 模板移动(Template Move) 状态,选择 添加链接(Add Link),然后将其连接到 消失(Vanish)。
-
在检查器中,点击 + 添加条件(Add Condition) 按钮。
-
选择 HPIsZero。
-
保留默认设置(TargetType: This Node)并添加它。
如果您的链接与示例匹配,则设置完成。
将敌人放置在 stage1 场景中
现在敌人已准备就绪,让我们将其与玩家一起放置在 stage1 中。
-
将编辑器视图从 脚本(Script) 切换到 2D。
-
将场景标签切换到 stage1。
-
在场景窗口中,选择 玩家(Player) 节点。
-
选中玩家后,从文件系统(FileSystem)中将 enemy.tscn 拖入场景,将其放置在玩家的右侧。
-
测试运行游戏。
如果一切设置正确,敌人将每 3 秒左右巡逻,并在被 3 发子弹击中后消失。
故障排除检查清单
-
敌人不左右移动:
检查 模板移动(Template Move) 状态设置。
-
敌人在掉头时不翻转:
检查 敌人节点的动画集(Animation Set),并确认模板移动状态已分配正确的动画。
-
敌人在被击中 1 次后消失:
检查敌人的 BaseSettings 中的 HP、最大 HP(Max HP) 和 无敌(Invincibility) 设置。
-
子弹无法击中敌人:
检查敌人的 HitArea 碰撞层/掩码(CollisionLayer/Mask) 和子弹的 AttackArea 碰撞层/掩码(CollisionLayer/Mask)。
-
子弹在撞击时不消失:
检查子弹的 移动 → 消失(Move → Disappear) 链接,并确认消失状态已设置 RemoveSelf 动作。
为玩家添加伤害处理
至此,我们已达成本部分的目标:“玩家可以通过射击击败敌人。”
然而,仍存在问题:敌人已有攻击碰撞箱,但玩家在被击中时目前没有任何反应。
此外,由于玩家也拥有攻击碰撞箱,目前仅通过碰撞即可击败敌人。
让我们调整玩家的设置,以实现以下目标:
- 玩家在被击中时做出反应。
- 播放**“受到伤害”动画**。
- 被击中后应用无敌时间。
- 正确调整碰撞箱和攻击箱。
- 最后,在可视化脚本中添加相应的行为。
在 BaseSettings 中调整无敌时间
接下来,让我们配置无敌时间。
由于这是针对玩家的,最好给予他们稍长的无敌持续时间。我们将它设置为1 秒,闪烁间隔为 0.2 秒。
此外,我们应在无敌期间禁用碰撞体(hitbox)。
即使玩家在此期间不会损失生命值,除非我们禁用碰撞体,否则系统仍会记录与攻击的碰撞。
-
选择 BaseSettings 节点。
-
在检查器(Inspector)中,将 Blink Duration 从 1.0 更改为 0.2。
-
展开位于“闪烁间隔”属性下方的 Disabled Hit Collision List (Array…),然后点击 + Add Element。
-
点击并设置为 New DisableCollisionData。
-
当它变为 DisableCollisionData 后,点击它以展开。
-
按下 Assign 按钮。
-
将出现节点选择窗口。选择 HitCollision 并按下 OK。
现在,每当玩家受到伤害时,他们的碰撞体将在 1 秒内被禁用。