第 4 章:让它真正成为一个“游戏”
在上一章中,我们完成了游戏玩法的基础内容,
实现了玩家可以发射子弹并击败敌人的功能。
在本章中,我们将更进一步,
把这个项目打磨成一个真正可以游玩的游戏。
要让它成为“游戏”,还缺少什么?
在当前版本中,玩家可以移动,敌人也已经存在,
但仍然缺少一些关键要素。
完成示例
扩展 Stage1(关卡扩展)
首先,让我们通过绘制更多的瓦片来扩展关卡。
由于关卡会变得更大,玩家最终会移动到当前摄像机显示范围之外,因此我们还需要确保摄像机会跟随玩家移动。
绘制更多瓦片
关卡地形是通过 Base(TileMapLayer) 节点创建的,因此我们将使用这个节点来扩展舞台。
-
切换到 stage1 场景标签页。
-
在 Scene(场景) 窗口中,选择 Base(TileMapLayer) 节点。
-
在底部窗口中,打开 TileMap 选项卡,并选择一个瓦片。
-
在右侧的空白区域自由放置瓦片。为了让关卡的可玩性保持良好,请注意以下平衡原则:
当你布置好足够的地形后,就可以进入下一步了。
「いいね!」 1
让摄像机跟随玩家
在 ACTION GAME MAKER 中,摄像机的跟随是通过一个叫做 Target ID 的系统来控制的。
你还记得在创建玩家时添加的 CameraTargetSettings 节点吗?这个节点中有一个名为 Target ID 的属性。
摄像机节点 ZoomCamera2D 也同样拥有 Target ID 属性。
当摄像机和某个游戏对象拥有相同的 Target ID 时,摄像机会自动跟随该对象。
下面我们将为 ZoomCamera2D 和玩家的 CameraTargetSettings 设置相同的 Target ID。
为 InitialCamera(ZoomCamera2D)设置 Target ID
-
切换到 Stage1 场景标签页,选择 InitialCamera(ZoomCamera2D) 节点。
-
在 Inspector 中,展开 Target ID(Array…) 属性。
-
点击 + Add Element 按钮。
-
会出现一个文本框。删除默认的 <null>,然后输入 player。
为玩家的 CameraTargetSettings 节点添加 Target ID
-
切换到 player 场景标签页。
-
选择 CameraTargetSettings 节点。
-
在 Inspector 的 Target ID 字段中输入 player。
测试扩展后的关卡
现在,让我们运行游戏来测试扩展后的关卡是否正常工作。
尝试让玩家一直移动到关卡最右侧。
如果一切设置正确,摄像机应该会平滑地跟随玩家移动。
检查清单
「いいね!」 1
为玩家添加“死亡”效果:创建粒子效果(Particles)
和敌人一样,当玩家的 HP 归零时,也应该被击败。
由于当前的角色图集中并没有合适的“死亡动画”帧,这里我们将使用 粒子效果(Particles) 来表现玩家被击败时的视觉演出。
什么是粒子(Particles)?
粒子本质上是大量分散的小图像,通过它们的运动和变化来构成视觉效果。
可以把它想象成彩带或烟花——单个元素很小,但组合起来就会形成有冲击力的画面。
在 Godot Engine 中,通常使用 GPUParticles2D 或 CPUParticles2D 节点来制作粒子效果。
而在 ACTION GAME MAKER 中,粒子效果是通过 ParticleObject 节点来管理的。
ParticleObject 内置了 20 种以上的粒子模板,可以直接使用,非常方便。
创建粒子对象(Particle Object)
创建粒子对象的流程与创建普通 Game Object 完全相同。
-
创建一个 新的场景标签页。
-
在创建根节点时,选择 GameObject。
-
将 Object Name 设置为 DeathParticle,
Template 选择 particles,然后点击 Create。
-
在 Scene 窗口中,选中新创建的 DeathParticle 节点。
-
在 Inspector 中,将 Particle Template 从 None 改为 Fireworks。
-
此时会自动添加一个 GPUParticles2D 节点。
-
在 GPUParticles2D 的 Inspector 中,勾选 Emitting 属性,使粒子开始发射。
-
现在,你应该可以在场景视图中看到类似烟花的粒子效果正在播放。
最后,右键点击 [Unsaved](*) 标签页,将场景保存为 deathparticle.tscn。
「いいね!」 1
为玩家的 Visual Script 添加“死亡(Death)”状态
关于“死亡(Death)状态”的思考
当玩家的 HP 变为 0 时,角色应当停止行动,并播放我们刚刚制作的 死亡粒子效果(Death Particle)。
从结构上来看,将这个状态从 AnyState 连接是最合理的,但这里存在一个问题:
如下图所示,目前只要玩家与敌人的攻击发生碰撞,就会从 AnyState 转移到 Take Damage 状态,而不管当前处于什么状态。
当 HP = 0 时,说明玩家已经“死亡”,但如果不做额外处理,就有可能在 Death 状态中再次触发 Take Damage 状态。
为了解决这个问题,我们需要在 Take Damage 的切换条件中追加一个限制条件:
“HP ≠ 0(HP is not Zero)”
这样一来,当玩家已经死亡时,就不会再进入受伤状态了。
创建“Death(死亡)状态”
由于没有专门的死亡动画帧,这里我们将复用 DamageTaken 动画。
为了让死亡看起来更加明确,我们会再叠加一个 滤镜效果(Filter),让角色逐渐消失。
-
打开 Player 场景。
-
将编辑器视图从 2D 切换到 Script。

-
在 Take Damage 状态附近的空白区域右键,选择 Add State。
-
将新建的 State001 重命名为 Death。
-
在 Animation 中选择 DamageTaken。
-
展开 Action Settings。
-
勾选 Ignore Movement Input(忽略移动输入)。
-
点击 + Add Executable Action。
-
选择 DisplayParticle。
-
在 Particle Object Path 中点击
图标,选择之前创建的 DeathParticle.tscn。
-
点击 Add。
-
再次点击 + Add Executable Action。
-
选择 ApplyObjectFilter。
-
将 Filter Type 设为 Transparent,
Finish Time 设为 3.0 秒。
-
点击 Add。
-
如果执行动作列表与下图一致,则 Death 状态 已完成。
将 AnyState 连接到 “Death” 状态
-
右键 AnyState → Add Link → 连接到 Death。
-
点击 + Add Other Condition。
-
选择 HPIsZero 并点击 Add。
为 “Take Damage” 的切换添加限制条件
最后一步,是确保当 HP 已经为 0 时,不会再触发 Take Damage。
我们可以通过 反转条件(Is Reversed) 来实现这一点。
-
选中 AnyState → Take Damage 的链接。
-
点击 + Add Condition。
-
选择 HPIsZero。
-
勾选 Is Reversed,将条件反转为 “HP ≠ 0”。
-
如果在条件列表中看到 ≠ 图标高亮,说明设置正确。
测试“死亡”状态
现在进行测试。
由于玩家的初始 HP 设置为 1,只要被敌人攻击一次,就会进入死亡状态。
如果一切正常:
- 被击中时会生成 死亡粒子效果
- 玩家角色会逐渐透明消失
- 游戏结束后,按 F5 可重新开始
故障排查(Troubleshooting)
-
粒子没有出现
→ 检查 DeathParticle.tscn 是否正确,以及 DisplayParticle 动作的设置。
-
角色没有渐隐消失
→ 确认 ApplyObjectFilter 的参数是否正确。
-
死亡后仍然触发受伤状态
→ 重新检查 AnyState → Take Damage 链接中的 HPIsZero(反转) 条件。
创建 HP 条(HP Bar)
现在玩家一击就倒显得有些苛刻了,所以我们先来提高玩家的 HP。
不过,一旦玩家拥有了更多 HP,就需要一种方式来直观地显示剩余体力。
为此,我们将创建一个 HP 条(HP Bar)。
在 ACTION GAME MAKER 中,可以使用 SimpleGauge 或 ImageGauge 节点来显示各种数值条。
本教程中我们将使用 SimpleGauge。
另外,由于现在摄像机会跟随玩家移动,如果把 HP 条放在和玩家相同的层级中,它就会被带着一起移动,甚至跑出画面。
因此,像 HP 条这样始终需要显示在屏幕上的元素,应该放在 UI 层(UI Layer) 中。
关于 UI Layer(UI 层)
你可能还记得之前提到过,ACTION GAME MAKER 的层结构大致如下所示。
其中 UI 层 和 屏幕效果层(Screen Effect Layer) 是不会受到摄像机影响的特殊层。
这意味着:
- 放在 UI 层 的节点会始终显示在画面上
- 非常适合用于 HP 条、分数、UI 按钮等
- Screen Effect Layer 通常用于通过动作触发的画面特效
在本节中,我们将使用 UI 层 来放置 HP 条。
将玩家的 HP 和 Max HP 设为 10
-
选择玩家对象中的 BaseSettings 节点。
-
在 Inspector 中,将 HP 和 Max HP 都从 1 改为 10。
添加并设置 SimpleGauge 节点
-
切换到 stage1 场景标签页,并将编辑器视图从 Script 切换回 2D。

-
在 Scene 面板中选择 UI 节点。
-
点击 Scene 面板左上角的 +(Add Child Node) 按钮。
-
选择 SimpleGauge,然后点击 Create。
-
初始状态下,Gauge 看起来会被压扁。
-
拖动橙色控制点,将其调整到合适的大小(可参考教程示例图)。
-
UI 层的可视范围由细蓝线标示。
将 HP 条移动到该范围内的 左上角。
将 HP 条与玩家的 HP 变量关联
-
在 Inspector 中,将 Variable Type 设置为 Object。
-
此时会出现 Specify Target Object Path。
点击右侧的
图标。
-
选择 player.tscn,然后点击 Open。
-
Variable Name 会自动显示为 hp。
这是用作“当前值”的变量名,保持不变即可。
-
勾选 Use Variable as Max Value(使用变量作为最大值)。
-
再次重复步骤 9–10,重新指定一次 player.tscn。
-
此时 Max Value Variable 可能默认为 object_id。
将它改为 max_hp。
- 这表示 HP 条的最大值将使用玩家的 Max HP。
测试 HP 条
点击 Test Play 运行游戏。
如果设置正确,你应该能看到:
-
HP 条显示在画面的左上角
-
当玩家受到伤害时,HP 条会相应减少
故障排查(Troubleshooting)
-
HP 条没有显示
→ 确认 SimpleGauge 是 UI 层的子节点,并且位于蓝色可视范围内。
-
游戏开始时 HP 很低
→ 检查玩家 BaseSettings 中的 HP 是否设置为 10。
-
即使有 Max HP,HP 仍然瞬间归零
→ 确认:
- BaseSettings 中 Max HP = 10
- SimpleGauge 的 Max Value Variable 正确设置为 max_hp
设置“掉落死亡(Fall Death)”
在测试游戏时,你可能已经注意到:
当玩家掉进坑里时,会一直无限下落。
现在就来解决这个问题,让玩家在掉进深坑时被判定为失败(Death)。
实现思路分为两步:
- 限制摄像机的移动范围,防止摄像机无限向下追踪
- 当玩家离开摄像机显示范围时,让其进入 Death 状态
限制 InitialCamera(ZoomCamera2D)的移动范围
-
选择 InitialCamera 节点。
-
在 Inspector 中展开 Limits(限制)部分。
-
将 Bottom 的值从 10000000 改为 500。
- 这表示:
摄像机在红绿坐标轴交点(原点)下方最多只会跟随 500 像素。
-
进行一次测试运行(Test Play)。
- 如果设置正确:
- 摄像机会继续水平和向上跟随玩家
- 但在向下方向到达限制后会停止继续下移
常见问题(Troubleshooting)
- 画面什么都看不到:
说明关卡整体可能不在原点附近。
可以尝试将 Bottom 的值改成 1000 或 2000,直到画面显示正常为止。
在玩家的 Visual Script 中加入“掉落失败”判定
由于我们已经创建好了 Death 状态,这里只需要在现有的
AnyState → Death 链接中再追加一个条件即可。
这次要用到的条件是 OffScreen(离开画面)。
操作步骤
-
切换到 Player 场景,并将编辑器视图切换为 Script。
-
选中 AnyState → Death 的链接。
-
点击 + Add Condition。
-
选择条件 OffScreen。
-
将 Data Type 从 Unset 改为 This Node。
-
将 Connection With Previous Condition 设置为 OR,然后点击 Add。
-
确认条件列表显示如下内容:
这表示:
“HP 为 0 或者 玩家离开画面范围 → 进入 Death 状态”
测试“掉落死亡”
再次运行游戏,让玩家掉进坑里。
如果设置正确:
- 当玩家离开摄像机的可视范围时
- 会触发 Death 状态
- 并播放之前设置的 烟花粒子效果
- 表示玩家已被击败
故障排查(Troubleshooting)
- 掉进坑里没有死亡:
→ 检查 AnyState → Death 的条件是否为:
HPIsZero OR OffScreen
思考“击败 5 个敌人即可通关”:变量的处理方式
我们需要一种方法来从 5 开始倒数。
每当一个敌人被击败,这个数值就减少 1,当它变成 0 时,游戏就会触发 通关(Game Clear) 事件。
为此,我们将使用一个叫做 变量(Variable) 的概念。
什么是变量(Variable)?
变量 就像是一个用来存放数值的容器。
例如,我们之前使用过的玩家 HP(生命值),本质上就是一个变量。
当玩家被敌人的攻击命中时,这个 HP 容器里的数值就会减少 1。
在 ACTION GAME MAKER 中,变量主要有两种定义方式:
- 使用对象上的 VariableSettings 节点
- 使用整个项目共用的 Project Variables(项目变量)
我们之前使用的 HP,就属于第一种类型。
对象变量 与 项目变量 的区别
-
对象变量(VariableSettings)
- 绑定在某一个对象上
- 当对象被删除时,变量也会随之消失
-
项目变量(Project Variables)
- 全项目共通的全局变量
- 在项目运行期间始终存在
- 适合用来管理跨场景、跨对象的数据
在实际使用中:
“剩余敌人数量”应该用哪种变量?
从技术上来说,两种方式都可以实现。
但由于这个数值会被 多个对象(敌人) 同时操作,因此我们这里选择使用 项目变量(Project Variable)。
整体流程将是:
如何实现通关流程(Clear Sequence)
我们将创建一个专门用于管理击败数的游戏对象。
这个对象将被放置在 UI 层 中,使其始终可见。
和 HP 条类似,它也会显示当前还剩多少敌人,让玩家一目了然。
具体步骤如下:
-
创建一个 项目变量(Project Variable):
Remaining Enemies(剩余敌人数量)
-
在 敌人的 “Vanish” 状态 中,
添加一个动作,用来让该变量 -1
-
在 UI 层创建一个 Clear Event Object(通关管理对象),
持续监视 “Remaining Enemies”,
当其数值变为 0 时,触发通关演出
在敌人的 “Vanish(消失)” 状态中添加动作
在 ACTION GAME MAKER 中,修改变量需要使用 Change Property(更改属性) 动作。
由于该动作支持基本的四则运算(加、减、乘、除),我们可以直接实现如下逻辑:
Remaining Enemies -= 1
(剩余敌人数量减 1)
操作步骤
-
打开 enemy 场景标签页,并将编辑器视图切换到 Script。
-
选中 Vanish 状态,点击 + Add Executable Action。
-
选择 ChangeObjectProperty。
-
按照以下内容进行设置:
-
Target Object Type(目标对象类型):Project Database
-
Database Type(数据库类型):Project Variable
-
Record Name(记录名):Remaining Enemies
-
Expression(运算符):-=
-
Constant Value(常量值):1
一共有 5 个项目 需要设置,请逐项确认是否正确。
通过这个动作,项目变量 Remaining Enemies 将会减少 1。
-
最后,调整执行动作的顺序。
动作是 从上到下 执行的,如果 Vanish Self(RemoveSelf) 比 Change Property 先执行,那么变量将不会被更新。
为什么要使用 -=,而不是只用 -?
在编程中,-= 是一种简写运算符,其含义是:
新值 = 原来的值 − 1
也就是说,它在一步中同时完成了:
如果只使用 -(减号)而不带 =,
系统并不知道要把计算结果存到哪里,
因此变量的值实际上并不会发生改变。
创建 UI 对象 “Remaining Enemies Manager(剩余敌人管理器)”
我们将创建一个 UI 对象,用来管理 Remaining Enemies(剩余敌人数量) 这个项目变量。
这个对象将负责两件事:
- 显示当前的 Remaining Enemies 数值
- 当该数值变为 0 时,触发游戏通关(Clear)流程
为了让显示更直观,我们会在 UI 中显示一个 敌人的图标(Sprite2D),
并在其旁边通过动作显示 Remaining Enemies 的数值。
敌人图标可以直接复用之前使用的 enemy.png。
创建 Remaining Enemies Manager 对象
-
将编辑器视图切换到 2D。
-
打开一个 新的场景标签页,在创建根节点时选择 GameObject。
-
按如下方式设置:
- Object Name:
RemainingEnemiesManager
- Template:
UI
- Type:
Empty
然后点击 Create。
-
保存新创建的场景。
-
从 FileSystem 中,将 enemy.png(敌人使用的精灵图像)
拖拽到编辑器视图中 红色与绿色坐标轴交叉点左侧的空白区域。
-
系统会自动创建一个名为 Enemy 的 Sprite2D 节点。
- 在 Godot 中,当你将图像文件直接拖入编辑器视图时,
会自动生成一个 Sprite2D 节点,并将该图像设置为其纹理。
配置 “Remaining Enemies Manager” 的可视化脚本(显示变量)
首先,我们先专注于显示变量本身。
这里只需要一个状态 “Count”,用于显示项目变量 Remaining Enemies 的当前值即可。
要显示变量,我们将使用 DisplayText(显示文本) 动作。
创建 “Count” 状态
-
在 Scene 窗口中,选中 RemainingEnemiesManager(GameObject) 节点,点击
+(Attach Script)。
-
创建脚本 RemainingEnemiesManager.vs。
-
将默认的 State001 重命名为 Count。
-
添加 DisplayText 执行动作,并按如下方式设置 Basic Settings(基础设置):
-
Text Type(文本类型):Variable
-
Variable Source(变量来源):Data Management
-
Database Type(数据库类型):Project Variables
-
Record Name(记录名):Remaining Enemies
-
接着按如下方式设置 Layout & Action(布局与行为):
-
Unlimited Duration(无限持续时间):On
-
Font(字体):New SystemFont
-
Font Size(字体大小):64
-
Display Size(显示区域大小):x = 80, y = 80
-
Margins(上 / 左 / 右 / 下):全部设为 0
-
Horizontal Alignment(水平对齐):Center
-
Vertical Alignment(垂直对齐):Center
关于 “DisplayText” 动作中位置的说明
该动作会创建一个指定大小的文本框,
并以参考点为中心显示文本(或变量值),持续指定的时间。
当参考点设置为 “This object’s center(本对象的中心)” 时,
这个中心点指的是 原点(红色与绿色坐标轴的交点)。
在当前设置中:
- 创建了一个 80×80 像素 的文本框
- 文本框以原点为中心
- 文本在框内居中显示
- 显示时间为 无限
测试 “Count” 的显示效果
接下来把它放进场景中进行测试。
由于我们希望它始终可见,因此需要把它放在 UI 层。
-
切换到 stage1 场景标签页,并将编辑器视图切换为 2D。

-
在 Scene 窗口中,选中 UI(CanvasLayer) 下的 SimpleGauge 节点。
-
在 FileSystem 中选中 RemainingEnemiesManager.tscn,
将其拖拽到 UI 层蓝色边框内的右上角区域。
-
运行测试并确认:
故障排查
-
图标和数字都没有显示:
请确认该对象是 UI 层的子节点,并且位于 蓝色边框(UI 显示区域) 内。
-
图标显示了但数字没有:
请确认 Remaining Enemies Manager 中:
- 图标位置在 原点附近
- Count 状态里的 DisplayText 动作设置正确
-
击败敌人后数字没有变化:
请检查敌人对象中 Vanish 状态的执行顺序,
必须是 先 Change Property,再 RemoveSelf。
创建通关流程(Clear Sequence)
接下来,我们来制作 通关演出(Clear Sequence)。
这里同样会使用 DisplayText 动作。
为了让玩家明确感受到“通关了”,
我们会在画面中央大字显示 “STAGE CLEAR”。
通关的触发条件是:
项目变量 Remaining Enemies 的值变为 0。
设置 “Stage Clear” 状态
-
切换到 RemainingEnemiesManager 场景标签页,并将编辑器视图切换为 Script。
-
在 Count 状态附近,右键选择 Add State。
-
将新建的状态重命名为 Stage Clear。
-
点击 + Add Executable Action。
-
选择 DisplayText。
-
按如下内容进行设置(项目较多,请逐项确认):
-
Text Body(文本内容):STAGE CLEAR
-
Unlimited Duration(无限持续时间):On
-
Font(字体):New SystemFont
-
Font Size(字体大小):96
-
Display Area(显示区域):x = 1200, y = 120
-
Horizontal Alignment(水平对齐):Center
-
Vertical Alignment(垂直对齐):Center
-
Reference Point(参考点):Use Scene as Base
-
Anchor(锚点):Center
什么是 “Use Scene as Base”?
这表示显示位置不是以该对象为基准,而是以**整个游戏画面(摄像机所显示的区域)**为基准。
在本设置中,一个 1200×120 的文本框会被放置在画面中央,
而 STAGE CLEAR 会在该文本框中居中显示。
-
右键 Count 状态 → Add Link → 连接到 Stage Clear。
-
点击 + Add Condition。
-
选择 SwitchVariableChanged。
-
按如下方式设置条件:
- Variable Type(变量类型):Variable
- Target Type(目标类型):Project Variable
- Database Record Name(记录名):Remaining Enemies
- Variable Condition(条件):
=
(这表示当 Remaining Enemies == 0 时触发状态切换。)
测试通关流程
首先,需要在关卡中放置足够的敌人。
请一共放置 5 个敌人,然后确认通关流程是否正常触发。
-
切换到 stage1 场景标签页,并将编辑器视图设为 2D。
-
在 BaseLayer 下,选中一个子节点(例如 enemy 或 player),以便进行放置操作。
-
从 FileSystem 中拖拽 enemy.tscn 到关卡中,放置一个敌人。
-
重复上述操作,直到一共放置 enemy5(5 个敌人)。
-
开始测试运行。
故障排查
第 4 章 回顾
在本章中,我们学习了以下内容,使游戏具备了作为一个真正游戏的基础:
- 摄像机跟随 的机制
- 粒子效果 的使用
- UI 的显示(HP 条 & 剩余敌人数)
- 变量(Variable)的使用与管理
这些功能让游戏不仅能动起来,还具备了:
- 实时 UI 显示
- 游戏失败判定
- 游戏通关判定
- 以及简洁流畅的关卡体验
不过目前的表现仍然比较简单,缺少音效与背景设定,整体表现比较单调。
在下一章——第 5 章 中,我们将进一步提升游戏的完整度,通过添加:
音效(Sound Effects / BGM)
背景与美术表现设置
将项目导出,使任何人都可以游玩
准备好进一步打磨你的游戏吧!
