Heads up display¶
The final piece our game needs is a User Interface (UI) to display things like score, a "game over" message, and a restart button.
Create a new scene, 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.
Węzeł CanvasLayer pozwala nam narysować nasze elementy interfejsu użytkownika na warstwie będącą przed resztą gry, tak aby wyświetlane przez niego informacje nie były zakryte żadnymi elementami gry, takimi jak gracz lub przeciwnik.
HUD powinien wyświetlić następujące informacje:
Wynik, zmieniany przez
ScoreTimer
.Wiadomości takie jak "Koniec Gry" lub "Przygotuj Się!"
Przycisk "Start" rozpoczyna grę.
Podstawowym węzłem elementów interfejsu użytkownika jest Control. Aby utworzyć nasz interfejs użytkownika, będziemy używać dwóch typów węzła ref:Control <class_Control> - Label oraz Button.
Utwórz je jako dzieci węzła HUD
:
Label nazwany
ScoreLabel
.Label nazwany
Message
.Przycisk Button o nazwie
StartButton
.Timer o nazwie
MessageTimer
.
Domyślna czcionka dla węzłów Control
jest mała i nie skaluje się dobrze. W zasobach gry znajduje się plik czcionki o nazwie "Xolonium-Regular.ttf". Aby użyć tej czcionki, wykonaj następujące czynności dla każdego z trzech węzłów Control
:
Under Theme overrides > Fonts click on the empty box and select "New DynamicFont"

Click on the "DynamicFont" you added, and under Font > FontData, choose "Load" and select the "Xolonium-Regular.ttf" file.

Set the "Size" property under Settings
, 64
works well.

Once you've done this on the ScoreLabel
, you can click the down arrow next
to the Font property and choose "Copy", then "Paste" it in the same place
on the other two Control nodes.
Informacja
Anchors and Margins: Control
nodes have a position and size,
but they also have anchors and margins. Anchors define the origin -
the reference point for the edges of the node. Margins update
automatically when you move or resize a control node. They represent
the distance from the control node's edges to its anchor.
Uporządkuj węzły w sposób pokazany poniżej. Kliknąć przycisk "Układ", aby ustawić dla węzła Control układ:

Węzły można przeciągnąć ręcznie lub, aby uzyskać bardziej precyzyjne rozmieszczenie, należy użyć następujących ustawień:
ScoreLabel¶
Layout : "Top Wide"
Tekst:
0
Wyrównanie: "Wyśrodkowany"
Wiadomość¶
Układ : "Środek"
Tekst :
Dodge the Creeps!
Wyrównanie: "Wyśrodkowany"
Autowrap : "On"
Podłączenie HUD do Main¶
Teraz, kiedy już stworzyłeś scenę HUD
, zapisz ją i wróć do Main`. Stwórz instancję HUD
w Main
tak, jak zrobiłeś to Player
scenę i umieść ją na dole drzewa. Pełne drzewo powinno wyglądać tak, więc upewnij się, że niczego nie przegapiłeś:

Teraz musimy podłączyć funkcję HUD
do naszego skryptu Main
. Wymaga to paru poprawek do sceny Main
:
In the Node tab, connect the HUD's start_game
signal to the new_game()
function of the Main node by typing "new_game" in the "Receiver Method" in the
"Connect a Signal" window. Verify that the green connection icon now appears
next to func new_game()
in the script.
W new_game()
, zaktualizuj wyświetlany wynik i pokaż komunikat "Przygotuj się":
$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();
W game_over()
musimy wywołać odpowiednią funkcję w HUD
:
$HUD.show_game_over()
GetNode<HUD>("HUD").ShowGameOver();
_hud->show_game_over();
Na koniec dodaj to do on_on_ScoreTimer_timeout()
, aby wyświetlacz był zsynchronizowany ze zmieniającym się wynikiem:
$HUD.update_score(score)
GetNode<HUD>("HUD").UpdateScore(Score);
_hud->update_score(score);
Teraz jesteś gotowy do gry! Kliknąć przycisk "Uruchom projekt". Zostaniesz poproszony o wybranie głównej sceny, więc wybierz Main.tscn
.
Removing old creeps¶
If you play until "Game Over" and then start a new game right away, the creeps from the previous game may still be on the screen. It would be better if they all disappeared at the start of a new game. We just need a way to tell all the mobs to remove themselves. We can do this with the "group" feature.
In the Mob
scene, select the root node and click the "Node" tab next to the
Inspector (the same place where you find the node's signals). Next to "Signals",
click "Groups" and you can type a new group name and click "Add".

Now all mobs will be in the "mobs" group. We can then add the following line to
the new_game()
function in Main
:
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");
The call_group()
function calls the named function on every node in a
group - in this case we are telling every mob to delete itself.
The game's mostly done at this point. In the next and last part, we'll polish it a bit by adding a background, looping music, and some keyboard shortcuts.