游戏信息显示¶
我们的游戏最后还需要用户界面(User Interface,UI),显示分数、“游戏结束”信息、重启按钮。
创建新场景,然后添加一个 CanvasLayer 节点并命名为 HUD
。“HUD”是“heads-up display”(游戏信息显示)的缩写,是覆盖在游戏视图上显示的信息。
CanvasLayer 节点可以让我们在游戏的其他部分的上一层绘制 UI 元素,这样它所显示的信息就不会被任何游戏元素(如玩家或敌人)所覆盖。
HUD 中需要显示以下信息:
得分,由
ScoreTimer
更改。消息,例如“Game Over”或“Get Ready!”
“Start”按钮来开始游戏。
UI 元素的基本节点是 Control 。要创建 UI,我们需使用 Control 下的两种节点:Label 和 Button。
创建以下节点作为 HUD
的子节点:
名为分数标签
ScoreLabel
的 Label。名为消息
Message
的 Label。名为开始按钮
StartButton
的 Button。名为信息计数器
MessageTimer
的 Timer。
点击 ScoreLabel
并在“检查器”的 Text
字段中键入一个数字。 Control
节点的默认字体很小,不能很好地缩放。游戏资产包中有一个叫作“Xolonium-Regular.ttf”的字体文件。 使用此字体需要执行以下操作:
在 Theme Overrides > Fonts 中,点击空白内容并选择“新建 DynamicFont”
点击您添加的“DynamicFont”,然后在 Font > Font Data 的下拉选项中选择“加载”并选择“Xolonium-Regular.ttf”文件。
设置 Settings
下的“Size”属性,设成 64
就可以。
在 ScoreLabel
上完成此操作后,可以单击 Font 属性旁边向下的箭头,然后选择“复制”,然后将其“粘贴”到其他两个 Control 节点的相同位置。
备注
锚点和边距:Control
节点具有位置和大小,但它也有锚点(Anchor)和边距(Margin)。锚点定义的是原点——节点边缘的参考点。移动或调整控件节点大小时,边距会自动更新。边距表示的是控件节点的边缘与锚点的距离。
按如下图所示排列节点。点击“布局”按钮以设置 Control 节点的布局:
你可以拖动节点以手动放置它们,或者要进行更精确的放置,请使用以下设置:
ScoreLabel¶
布局:“顶部全幅”
Text:
0
Align:“Center”
Message¶
布局:“水平居中全幅”
Text:
Dodge the Creeps!
Align:“Center”
Autowrap:“启用”
将 HUD 场景连接到 Main 场景¶
现在我们完成了 HUD
场景,保存并返回 Main
场景。和 Player
场景的做法一样,在 Main
场景中实例化 HUD
场景。如果您没有错过任何东西,完整的场景树应该像这样:
现在我们需要将 HUD
功能与我们的 Main
脚本连接起来。这需要在 Main
场景中添加一些内容:
在节点选项卡中,通过在“连接信号”窗口的“接收方法”中键入 new_game
,将 HUD 的 start_game
信号连接到主节点的 new_game()
函数。观察绿色的连接图标现在是否在脚本中的 func new_game()
左边出现。
在 new_game()
函数中,更新分数显示并显示“Get Ready”消息:
$HUD.update_score(score)
$HUD.show_message("Get Ready")
var hud = GetNode<HUD>("HUD");
hud.UpdateScore(Score);
hud.ShowMessage("Get Ready!");
_hud->update_score(score);
_hud->show_get_ready();
在 game_over()
中我们需要调用相应的 HUD
函数:
$HUD.show_game_over()
GetNode<HUD>("HUD").ShowGameOver();
_hud->show_game_over();
最后,将下面的代码添加到 _on_ScoreTimer_timeout()
以保持不断变化的分数的同步显示:
$HUD.update_score(score)
GetNode<HUD>("HUD").UpdateScore(Score);
_hud->update_score(score);
现在你可以开始游戏了!点击“运行项目”按钮。将要求你选择一个主场景,因此选择 Main.tscn
。
删除旧的小怪¶
如果你一直玩到“游戏结束”,然后重新开始新游戏,上局游戏的小怪仍然显示在屏幕上。更好的做法是在新游戏开始时清除它们。我们需要一个同时让所有小怪删除它自己的方法,为此可以使用“分组”功能。
在 Mob
场景中,选择根节点,然后单击检查器旁边的“节点”选项卡(在该位置可以找到节点的信号)。 点击“信号”旁边的“分组”,然后可以输入新的组名称,点击“添加”。
现在,所有小怪都将属于“mobs”(小怪)分组。我们可以将以下行添加到 Main
中的 new_game()
函数中:
get_tree().call_group("mobs", "queue_free")
// Note that for calling Godot-provided methods with strings,
// we have to use the original Godot snake_case name.
GetTree().CallGroup("mobs", "queue_free");
get_tree()->call_group("mobs", "queue_free");
call_group()
函数调用组中每个节点上的删除函数——让每个怪物删除其自身。
游戏在这一点上大部分已经完成。在下一部分和最后一部分中,我们将通过添加背景,循环音乐和一些键盘快捷键来对其进行一些润色。