Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

遊戲資訊顯示

我們的遊戲最後還需要使用者介面(User Interface,UI),顯示分數、“遊戲結束”資訊、重啟按鈕。

Create a new scene, click the "Other Node" button and add a CanvasLayer node named HUD. "HUD" stands for "heads-up display", an informational display that appears as an overlay on top of the game view.

使用 CanvasLayer 節點可以讓我們在遊戲上方的圖層上繪製 UI 元素,這樣上面顯示的資訊就不會被其他遊戲元素如玩家或怪物給蓋住。

HUD 需要顯示如下資訊:

  • 分數,會通過 ScoreTimer 來更改。

  • 訊息,如「Gamer Over」或「請準備!」

  • 用來開始遊戲的「Start」按鈕。

UI 元素所使用的基本節點是 Control 。我們需要使用兩種類型的 Control 節點來給這個遊戲建立 UI: Label (標籤)與 Button (按鈕)。

HUD 節點建立下列子節點:

  • Label ,命名為 ScoreLabel

  • Label ,命名為 Message

  • Button ,命名為 StartButton

  • Timer ,命名為 MessageTimer

點擊 ScoreLabel 並在屬性面板中的 Text 輸入一個數字。 Control 節點的預設字形很小,而且也縮放得不是很好。遊戲素材裡有包含了一個字形檔,檔名為「Xolonium-Regular.ttf」。依照下列步驟來使用這個字形:

在“Theme Overrides > Fonts”(主題覆蓋 > 字體)中選擇“載入”,然後選中“Xolonium-Regular.ttf”檔。

../../_images/custom_font_load_font.webp

字形尺寸仍然太小,請在“Theme Overrides > Font Sizes”(主題覆蓋 > 字形大小)下將其增加到 64 。當 ScoreLabel 完成此操作後,請重複對 MessageStartButton 節點做同樣的修改。

../../_images/custom_font_size.webp

備註

錨點與外邊距: Control 節點除了位置與大小之外,也可以設定錨點 (Anchor) 與外邊距 (Margin)。錨點定義原點(相對於節點邊緣的參考點)。外邊距則會在移動或縮放 Control 節點時自動更新。這兩個屬性的變化會反映出 Control 節點到錨點的距離。詳細說明請參考 doc_design_interfaces_with_the_control_nodes

請將節點如下圖排列。拖動節點可以手動放置,也可以使用"錨點預設(Anchor Preset)"進行更精確的定位。

../../_images/ui_anchor.webp

ScoreLabel

  1. 新增文字 0

  2. 將“Horizontal Alignment”和“Vertical Alignment”設定為 Center

  3. 為“Anchor Preset”選擇 Center Top

訊息

  1. Add the text Dodge the Creeps!.

  2. 將“Horizontal Alignment”和“Vertical Alignment”設定為 Center

  3. 將“Autowrap Mode”設定為 Word ,否則標籤只會有一行。

  4. 在“Control - Layout/Transform”中將“Size X”設定為 480 ,使用螢幕的完整寬度。

  5. 為“Anchor Preset”選擇 Center

StartButton

  1. TextStart

  2. 在“Control - Layout/Transform”中將“Size X”設定為 200、“Size Y”設定為 100,在邊框和文字之間新增間距。

  3. 為“Anchor Preset”選擇 Center Bottom

  4. 在“Control - Layout/Transform”中將“Position Y”設定為 580

MessageTimerWait Time 設為 2 ,將 One Shot 設為「開啟」。

現在將這個腳本新增至 HUD

extends CanvasLayer

# Notifies `Main` node that the button has been pressed
signal start_game

當我們想要暫時顯示訊息(如「Get Ready」)時可以呼叫這個函式。

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

當玩家輸了之後會呼叫這個函式。會在畫面上顯示 2 秒「Game Over」,然後回到標題畫面、暫停一下,最後顯示「Start」按鈕。

func show_game_over():
    show_message("Game Over")
    # Wait until the MessageTimer has counted down.
    await $MessageTimer.timeout

    $Message.text = "Dodge the Creeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    await get_tree().create_timer(1.0).timeout
    $StartButton.show()

當玩家輸了之後會呼叫這個函式。會在畫面上顯示 2 秒「Game Over」,然後回到標題畫面、暫停一下,最後顯示「Start」按鈕。

備註

需要暫停一下下的時候,除了使用 Timer 節點外也可以使用 SceneTree(場景樹)的 create_timer() 函式。當需要像上面的程式碼一樣新增一點延遲的時候很有用,上面的例子中我們用它來在顯示「Start」按鈕前增加一點點等待時間。

將以下更新分數程式碼新增到 HUD

func update_score(score):
    $ScoreLabel.text = str(score)

連接 MessageTimertimeout() 訊號與 ``StartButtonpressed() 訊號,並新增下列程式碼到新函式當中:

func _on_start_button_pressed():
    $StartButton.hide()
    start_game.emit()

func _on_message_timer_timeout():
    $Message.hide()

將 HUD 場景連接至 Main 場景

我們現在做好 HUD 場景了。讓我們回到 Main。像剛才實體化 Player 場景一樣,在 Main 場景中實體化 HUD。場景樹會看起來像這樣,檢查一下有沒有漏了什麼:

../../_images/completed_main_scene.webp

我們現在需要把 HUD 的功能連接到 Main 腳本。所以我們需要在 Main 場景內新增一點點東西:

在節點分頁中,設定 HUD 的 start_game 訊號的連接,在「連接訊號」視窗中將「Receiver 方法」設為「new_game」來將訊號連接到 Main 節點的 new_game() 函式。之後檢查看看腳本中的 ``func new_game()``旁邊有沒有出現綠色的連線圖示。

new_game() 中,需要更新分數並顯示「Get Ready」訊息:

$HUD.update_score(score)
$HUD.show_message("Get Ready")

game_over() 中我們需要呼叫對應的 HUD 函式:

$HUD.show_game_over()

最後,將這段程式碼加到 _on_ScoreTimer_timeout() 來讓分數改變的時候能同步顯示:

$HUD.update_score(score)

警告

Remember to remove the call to new_game() from _ready() if you haven't already, otherwise your game will start automatically.

現在已經可以執行遊戲了!點擊「執行專案」按鈕。接著會被要求選擇一個主場景,這裡我們選 Main.tscn

刪除舊的怪物

如果一直玩到「Game Over」並直接開始新遊戲的話,上一場遊戲的怪物可能還在畫面上。開始遊戲的時候如果能讓舊的怪物消失會更好。而我們只需要告訴 所有 怪物,刪除自己。我們可以在這裡使用「群組」功能。

Mob 場景中,先選擇根節點,然後點擊屬性面板旁邊的「節點」分頁(跟設定節點訊號的地方相同)。點擊「訊號」旁邊的「群組」,接著編輯器會讓你設定新群組名稱,最後點擊「新增」。

../../_images/group_tab.webp

現在所有的怪物都會被放在「mobs」群組內了。我們可以接著在 Main 腳本的 game_over() 函式中增加下面這行的程式碼:

get_tree().call_group("mobs", "queue_free")

call_group() 函式會呼叫群組中所有節點的指定名稱的函式——在這裡我們用來讓所有怪物刪除自己。

遊戲在這一點上大部分已經完成。在下一部分和最後一部分中,我們將通過新增背景,迴圈音樂和一些鍵盤快捷鍵來對其進行一些潤色。