Game1硬币收集 - 第4部分 用户界面 - Godot引擎游戏开发项目实践

第4部分 用户界面

您的游戏制作的最后一块是用户界面(UI)。这是一个界面,用于显示玩家在游戏过程中需要查看的信息。在游戏中,这也被称为平视显示器(HUD),因为信息在游戏视图的顶部显示为叠加。您还将使用此场景显示开始按钮。

HUD将显示以下信息:

  • 分数
  • 剩余时间
  • 消息,例如Game Over
  • 开始按钮

节点设置

创建一个新场景并添加名为HUD的CanvasLayer节点。CanvasLayer节点允许您在游戏剩余部分上方的图层上绘制UI元素,这样它显示的信息就不会被玩家或硬币等任何游戏元素所覆盖。

Godot提供了各种各样的UI元素,可用于创建从健康栏等指标到库存等复杂界面的任何内容。事实上,你用来制作这个游戏的Godot编辑器是使用这些元素在Godot中构建的。 UI元素的基本节点从Control扩展,并在节点列表中以绿色图标显示。要创建UI,您将使用各种控制节点来定位,格式化和显示信息。以下是完成后HUD的样子:

HUD界面

锚点和边距

控制节点具有位置和大小,但它们也具有称为anchors(锚点)和margins(边距)的属性。锚定义节点边缘相对于父容器的原点或参考点。边距表示从控制节点的边缘到其对应锚点的距离。移动控件节点或调整控件节点大小时,边距会自动更新。


信息标签

Label节点添加到场景并将其名称更改为MessageLabel。此标签将显示游戏的标题,以及游戏结束时的Game Over。此标签应以游戏屏幕为中心。您可以使用鼠标拖动它,但要精确放置UI元素,您应该使用Anchor属性。

选择View|Show Helpers显示帮助程序以显示可帮助您查看锚点位置的引脚,然后单击Layout菜单并选择HCenter Wide(水平居中):

Layout菜单

MessageLabel现在跨越屏幕的宽度并垂直居中。 Inspector中的Text属性设置标签显示的文本。把它设置为Coin Dash!并将AlignValign设置为Center

Label节点的默认字体非常小,因此下一步是分配自定义字体。向下滚动到Inspector中的Custom Fonts部分,然后选择New DynamicFont,如以下屏幕截图所示:

自定义字体

现在,单击DynamicFont,您可以调整字体设置。从FileSystem侧边栏中,拖动Kenney Bold.ttf字体并将其放在Font Data属性中。将Size设置为48,如以下屏幕截图所示:

字体属性

分数和时间显示

HUD的顶部将显示玩家的分数和时钟剩余的时间。这两个都是Label节点,排列在游戏屏幕的两侧。您可以使用Container节点来管理其位置,而不是单独定位它们。

Containers容器

UI容器自动排列其子Control节点(包括其他Containers)的位置。您可以使用它们在元素周围添加填充,居中,或按行或列排列元素。每种类型的Container都有特殊的属性来控制他们如何安排子项。您可以在检查器的Custom Constants部分中看到这些属性。

提示
请记住,容器会自动调整其子项。如果移动或调整Container节点内的Control,您会发现它会快速恢复到原始位置。您可以手动排列控件或使用容器排列它们,但不能同时排列两者。

MarginContainer节点添加到HUD。使用Layout菜单将锚点设置为Top Wide。在Custom Constants部分中,将Margin RightMargin TopMargin Left设置为10。这将添加一些填充,以便文本不会对着屏幕的边缘。

由于得分和时间标签将使用与MessageLabel相同的字体设置,因此如果您复制它,将节省时间。单击MessageLabel并按两次Ctrl + D(在macOS上为Cmd + D)以创建两个重复标签。拖动它们并将它们放在MarginContainer上以使它们成为子项。将一个命名为ScoreLabel,另一个命名为TimeLabel,并将Text属性设置为0。为ScoreLabel设置为Align to Left,为TimeLabel设置为Align to Right


通过脚本更新UI

将脚本添加到HUD节点。例如,该脚本将在其属性需要更改时更新UI元素,并在收集硬币时更新分数文本。请参阅以下代码:

extends CanvasLayer

signal start_game

func update_score(value):
    $MarginContainer/ScoreLabel.text = str(value)
func update_timer(value):
    $MarginContainer/TimeLabel.text = str(value)

Main场景的脚本将调用这些函数,以便在值发生变化时更新显示。对于MessageLabel,您还需要一个计时器,使其在短暂的一段时间后消失。添加Timer节点并将其名称更改为MessageTimer。在Inspector中,将其Wait Time设置为2秒,然后选中One Shot设置为On。这确保了在启动时,计时器只运行一次,而不是重复。添加以下代码:

func show_message(text):
    $MessageLabel.text = text
    $MessageLabel.show()
    $MessageTimer.start()

在此功能中,您将显示消息并启动计时器。要隐藏消息,请连接MessageTimertimeout()信号并添加以下内容:

func _on_MessageTimer_timeout():
    $MessageLabel.hide()

使用按钮

添加一个Button节点并将其名称更改为StartButton。此按钮将在游戏开始前显示,点击后,它将隐藏自身并向Main场景发送信号以启动游戏。将Text属性设置为Start并更改自定义字体,就像使用MessageLabel一样。在Layout菜单中,选择Center Bottom。这会将按钮放在屏幕的最底部,因此可以通过按向上箭头键或编辑Margin并将Top设置为-150,将Bottom设置为-50来将其向上移动一点。

单击按钮时,会发出信号。在StartButtonNode选项卡中,连接pressed()信号:

func _on_StartButton_pressed():
    $StartButton.hide()
    $MessageLabel.hide()
    emit_signal("start_game")

HUD发出start_game信号以通知Main,是时候开始新游戏了。


游戏结束

UI的最终任务是对游戏结束作出反应:

func show_game_over():
    show_message("Game Over")
    yield($MessageTimer, "timeout")
    $StartButton.show()
    $MessageLabel.text = "Coin Dash!"
    $MessageLabel.show()

在此函数中,您需要将Game Over消息显示两秒钟然后消失,这就是show_message()所做的事情。但是,您还希望在消息消失后​​显示开始按钮。 yield()暂停函数的执行,直到给定节点(MessageTimer)发出给定信号(timeout)。收到信号后,该功能继续,使您返回初始状态,以便您可以再次游戏。

文档
yield()


添加HUD到Main场景

现在,您需要设置Main场景和HUD场景之间的通信。将HUD场景的实例添加到主场景。在Main场景中,连接GameTimertimeout()信号并添加以下内容:

func _on_GameTimer_timeout():
    time_left -= 1
    $HUD.update_timer(time_left)
    if time_left <= 0:
        game_over()

每当GameTimer超时(每秒)时,剩余时间就会减少。接下来,连接Playerpickup()hurt()信号:

func _on_Player_pickup():
    score += 1
    $HUD.update_score(score)

func _on_Player_hurt():
    game_over()

游戏结束时需要做几件事,所以添加以下功能:

func game_over():
    playing = false
    $GameTimer.stop()
    for coin in $CoinContainer.get_children():
        coin.queue_free()
    $HUD.show_game_over()
    $Player.die()

此功能会暂停游戏,并循环显示硬币并删除剩余的任何内容,以及调用HUDshow_game_over()函数。

最后,StartButton需要激活new_game()函数。单击HUD实例并选择其new_game()信号。在信号连接对话框中,单击Make Function将函数设置为Off,然后在Method In Node字段中键入new_game。这会将信号连接到现有功能,而不是创建新功能。看看下面的截图:

激活new_game()

_ready()函数中删除new_game()并将这两行添加到new_game()函数中:

$HUD.update_score(score)
$HUD.update_timer(time_left)

现在,你可以玩游戏了!确认所有部件都按预期工作:分数,倒计时,游戏结束和重新启动等。如果您发现一块不起作用,请返回并检查您创建它的步骤,以及它与游戏其余部分连接的步骤。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342