第4部分 用戶界面
您的游戲制作的最后一塊是用戶界面(UI)。這是一個(gè)界面,用于顯示玩家在游戲過程中需要查看的信息。在游戲中,這也被稱為平視顯示器(HUD),因?yàn)樾畔⒃谟螒蛞晥D的頂部顯示為疊加。您還將使用此場(chǎng)景顯示開始按鈕。
HUD將顯示以下信息:
- 分?jǐn)?shù)
- 剩余時(shí)間
- 消息,例如Game Over
- 開始按鈕
節(jié)點(diǎn)設(shè)置
創(chuàng)建一個(gè)新場(chǎng)景并添加名為HUD的CanvasLayer節(jié)點(diǎn)。CanvasLayer節(jié)點(diǎn)允許您在游戲剩余部分上方的圖層上繪制UI元素,這樣它顯示的信息就不會(huì)被玩家或硬幣等任何游戲元素所覆蓋。
Godot提供了各種各樣的UI元素,可用于創(chuàng)建從健康欄等指標(biāo)到庫(kù)存等復(fù)雜界面的任何內(nèi)容。事實(shí)上,你用來(lái)制作這個(gè)游戲的Godot編輯器是使用這些元素在Godot中構(gòu)建的。 UI元素的基本節(jié)點(diǎn)從Control擴(kuò)展,并在節(jié)點(diǎn)列表中以綠色圖標(biāo)顯示。要?jiǎng)?chuàng)建UI,您將使用各種控制節(jié)點(diǎn)來(lái)定位,格式化和顯示信息。以下是完成后HUD的樣子:

錨點(diǎn)和邊距
控制節(jié)點(diǎn)具有位置和大小,但它們也具有稱為anchors(錨點(diǎn))和margins(邊距)的屬性。錨定義節(jié)點(diǎn)邊緣相對(duì)于父容器的原點(diǎn)或參考點(diǎn)。邊距表示從控制節(jié)點(diǎn)的邊緣到其對(duì)應(yīng)錨點(diǎn)的距離。移動(dòng)控件節(jié)點(diǎn)或調(diào)整控件節(jié)點(diǎn)大小時(shí),邊距會(huì)自動(dòng)更新。
信息標(biāo)簽
將Label節(jié)點(diǎn)添加到場(chǎng)景并將其名稱更改為MessageLabel。此標(biāo)簽將顯示游戲的標(biāo)題,以及游戲結(jié)束時(shí)的Game Over。此標(biāo)簽應(yīng)以游戲屏幕為中心。您可以使用鼠標(biāo)拖動(dòng)它,但要精確放置UI元素,您應(yīng)該使用Anchor屬性。
選擇View|Show Helpers顯示幫助程序以顯示可幫助您查看錨點(diǎn)位置的引腳,然后單擊Layout菜單并選擇HCenter Wide(水平居中):

MessageLabel現(xiàn)在跨越屏幕的寬度并垂直居中。 Inspector中的Text屬性設(shè)置標(biāo)簽顯示的文本。把它設(shè)置為Coin Dash!并將Align和Valign設(shè)置為Center。
Label節(jié)點(diǎn)的默認(rèn)字體非常小,因此下一步是分配自定義字體。向下滾動(dòng)到Inspector中的Custom Fonts部分,然后選擇New DynamicFont,如以下屏幕截圖所示:

現(xiàn)在,單擊DynamicFont,您可以調(diào)整字體設(shè)置。從FileSystem側(cè)邊欄中,拖動(dòng)Kenney Bold.ttf字體并將其放在Font Data屬性中。將Size設(shè)置為48,如以下屏幕截圖所示:

分?jǐn)?shù)和時(shí)間顯示
HUD的頂部將顯示玩家的分?jǐn)?shù)和時(shí)鐘剩余的時(shí)間。這兩個(gè)都是Label節(jié)點(diǎn),排列在游戲屏幕的兩側(cè)。您可以使用Container節(jié)點(diǎn)來(lái)管理其位置,而不是單獨(dú)定位它們。
Containers容器
UI容器自動(dòng)排列其子Control節(jié)點(diǎn)(包括其他Containers)的位置。您可以使用它們?cè)谠刂車砑犹畛洌又?,或按行或列排列元素。每種類型的Container都有特殊的屬性來(lái)控制他們?nèi)绾伟才抛禹?xiàng)。您可以在檢查器的Custom Constants部分中看到這些屬性。
提示
請(qǐng)記住,容器會(huì)自動(dòng)調(diào)整其子項(xiàng)。如果移動(dòng)或調(diào)整Container節(jié)點(diǎn)內(nèi)的Control,您會(huì)發(fā)現(xiàn)它會(huì)快速恢復(fù)到原始位置。您可以手動(dòng)排列控件或使用容器排列它們,但不能同時(shí)排列兩者。
MarginContainer節(jié)點(diǎn)添加到HUD。使用Layout菜單將錨點(diǎn)設(shè)置為Top Wide。在Custom Constants部分中,將Margin Right,Margin Top和Margin Left設(shè)置為10。這將添加一些填充,以便文本不會(huì)對(duì)著屏幕的邊緣。
由于得分和時(shí)間標(biāo)簽將使用與MessageLabel相同的字體設(shè)置,因此如果您復(fù)制它,將節(jié)省時(shí)間。單擊MessageLabel并按兩次Ctrl + D(在macOS上為Cmd + D)以創(chuàng)建兩個(gè)重復(fù)標(biāo)簽。拖動(dòng)它們并將它們放在MarginContainer上以使它們成為子項(xiàng)。將一個(gè)命名為ScoreLabel,另一個(gè)命名為TimeLabel,并將Text屬性設(shè)置為0。為ScoreLabel設(shè)置為Align to Left,為TimeLabel設(shè)置為Align to Right。
通過腳本更新UI
將腳本添加到HUD節(jié)點(diǎn)。例如,該腳本將在其屬性需要更改時(shí)更新UI元素,并在收集硬幣時(shí)更新分?jǐn)?shù)文本。請(qǐng)參閱以下代碼:
extends CanvasLayer
signal start_game
func update_score(value):
$MarginContainer/ScoreLabel.text = str(value)
func update_timer(value):
$MarginContainer/TimeLabel.text = str(value)
Main場(chǎng)景的腳本將調(diào)用這些函數(shù),以便在值發(fā)生變化時(shí)更新顯示。對(duì)于MessageLabel,您還需要一個(gè)計(jì)時(shí)器,使其在短暫的一段時(shí)間后消失。添加Timer節(jié)點(diǎn)并將其名稱更改為MessageTimer。在Inspector中,將其Wait Time設(shè)置為2秒,然后選中One Shot設(shè)置為On。這確保了在啟動(dòng)時(shí),計(jì)時(shí)器只運(yùn)行一次,而不是重復(fù)。添加以下代碼:
func show_message(text):
$MessageLabel.text = text
$MessageLabel.show()
$MessageTimer.start()
在此功能中,您將顯示消息并啟動(dòng)計(jì)時(shí)器。要隱藏消息,請(qǐng)連接MessageTimer的timeout()信號(hào)并添加以下內(nèi)容:
func _on_MessageTimer_timeout():
$MessageLabel.hide()
使用按鈕
添加一個(gè)Button節(jié)點(diǎn)并將其名稱更改為StartButton。此按鈕將在游戲開始前顯示,點(diǎn)擊后,它將隱藏自身并向Main場(chǎng)景發(fā)送信號(hào)以啟動(dòng)游戲。將Text屬性設(shè)置為Start并更改自定義字體,就像使用MessageLabel一樣。在Layout菜單中,選擇Center Bottom。這會(huì)將按鈕放在屏幕的最底部,因此可以通過按向上箭頭鍵或編輯Margin并將Top設(shè)置為-150,將Bottom設(shè)置為-50來(lái)將其向上移動(dòng)一點(diǎn)。
單擊按鈕時(shí),會(huì)發(fā)出信號(hào)。在StartButton的Node選項(xiàng)卡中,連接pressed()信號(hào):
func _on_StartButton_pressed():
$StartButton.hide()
$MessageLabel.hide()
emit_signal("start_game")
HUD發(fā)出start_game信號(hào)以通知Main,是時(shí)候開始新游戲了。
游戲結(jié)束
UI的最終任務(wù)是對(duì)游戲結(jié)束作出反應(yīng):
func show_game_over():
show_message("Game Over")
yield($MessageTimer, "timeout")
$StartButton.show()
$MessageLabel.text = "Coin Dash!"
$MessageLabel.show()
在此函數(shù)中,您需要將Game Over消息顯示兩秒鐘然后消失,這就是show_message()所做的事情。但是,您還希望在消息消失后??顯示開始按鈕。 yield()暫停函數(shù)的執(zhí)行,直到給定節(jié)點(diǎn)(MessageTimer)發(fā)出給定信號(hào)(timeout)。收到信號(hào)后,該功能繼續(xù),使您返回初始狀態(tài),以便您可以再次游戲。
文檔
yield()
添加HUD到Main場(chǎng)景
現(xiàn)在,您需要設(shè)置Main場(chǎng)景和HUD場(chǎng)景之間的通信。將HUD場(chǎng)景的實(shí)例添加到主場(chǎng)景。在Main場(chǎng)景中,連接GameTimer的timeout()信號(hào)并添加以下內(nèi)容:
func _on_GameTimer_timeout():
time_left -= 1
$HUD.update_timer(time_left)
if time_left <= 0:
game_over()
每當(dāng)GameTimer超時(shí)(每秒)時(shí),剩余時(shí)間就會(huì)減少。接下來(lái),連接Player的pickup()和hurt()信號(hào):
func _on_Player_pickup():
score += 1
$HUD.update_score(score)
func _on_Player_hurt():
game_over()
游戲結(jié)束時(shí)需要做幾件事,所以添加以下功能:
func game_over():
playing = false
$GameTimer.stop()
for coin in $CoinContainer.get_children():
coin.queue_free()
$HUD.show_game_over()
$Player.die()
此功能會(huì)暫停游戲,并循環(huán)顯示硬幣并刪除剩余的任何內(nèi)容,以及調(diào)用HUD的show_game_over()函數(shù)。
最后,StartButton需要激活new_game()函數(shù)。單擊HUD實(shí)例并選擇其new_game()信號(hào)。在信號(hào)連接對(duì)話框中,單擊Make Function將函數(shù)設(shè)置為Off,然后在Method In Node字段中鍵入new_game。這會(huì)將信號(hào)連接到現(xiàn)有功能,而不是創(chuàng)建新功能??纯聪旅娴慕貓D:

從_ready()函數(shù)中刪除new_game()并將這兩行添加到new_game()函數(shù)中:
$HUD.update_score(score)
$HUD.update_timer(time_left)
現(xiàn)在,你可以玩游戲了!確認(rèn)所有部件都按預(yù)期工作:分?jǐn)?shù),倒計(jì)時(shí),游戲結(jié)束和重新啟動(dòng)等。如果您發(fā)現(xiàn)一塊不起作用,請(qǐng)返回并檢查您創(chuàng)建它的步驟,以及它與游戲其余部分連接的步驟。