Up to date

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

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, 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.

Il nodo :ref:'CanvasLayer <class_CanvasLayer>' ci consente di disegnare i nostri elementi dell'interfaccia utente su un livello sopra il resto del gioco, in modo che le informazioni visualizzate non vengano coperte da elementi di gioco come il giocatore o i mob.

L'HUD deve mostrare le seguenti informazioni:

  • Punteggio, modificato da ''ScoreTimer''.

  • Un messaggio, ad esempio "Game Over" o "Get Ready!"

  • Un pulsante "Start" per iniziare il gioco.

Il nodo di base per gli elementi dell'interfaccia utente è :ref:'Control <class_Control>'. Per creare l'interfaccia utente, useremo due tipi di nodi :ref:'Control <class_Control>': :ref:'Label <class_Label>' e :ref:'Button <class_Button>'.

Crea i seguenti come figli del nodo HUD:

  • Label denominato ScoreLabel.

  • Label denominato Message.

  • Button denominato StartButton.

  • Timer denominato MessageTimer.

Fare clic su ScoreLabel e digitare un numero nel campo Testo nell'Inspector. Il tipo di font predefinito per i nodi Control è piccolo e non scala bene. C'è un file di font incluso nelle risorse di gioco chiamato "Xolonium-Regular.ttf". Per utilizzare questo font, eseguire le operazioni seguenti:

Under "Theme Overrides > Fonts", choose "Load" and select the "Xolonium-Regular.ttf" file.

../../_images/custom_font_load_font.webp

The font size is still too small, increase it to 64 under "Theme Overrides > Font Sizes". Once you've done this with the ScoreLabel, repeat the changes for the Message and StartButton nodes.

../../_images/custom_font_size.webp

Nota

Anchors: Control nodes have a position and size, but they also have anchors. Anchors define the origin - the reference point for the edges of the node.

Arrange the nodes as shown below. You can drag the nodes to place them manually, or for more precise placement, use "Anchor Presets".

../../_images/ui_anchor.webp

ScoreLabel

  1. Add the text 0.

  2. Set the "Horizontal Alignment" and "Vertical Alignment" to Center.

  3. Choose the "Anchor Preset" Center Top.

Messaggio

  1. Add the text Dodge the Creeps!.

  2. Set the "Horizontal Alignment" and "Vertical Alignment" to Center.

  3. Set the "Autowrap Mode" to Word, otherwise the label will stay on one line.

  4. Under "Control - Layout/Transform" set "Size X" to 480 to use the entire width of the screen.

  5. Choose the "Anchor Preset" Center.

StartButton

  1. Add the text Start.

  2. Under "Control - Layout/Transform", set "Size X" to 200 and "Size Y" to 100 to add a little bit more padding between the border and text.

  3. Choose the "Anchor Preset" Center Bottom.

  4. Under "Control - Layout/Transform", set "Position Y" to 580.

Sul MessageTimer, imposta Tempo d'attesa su 2 e imposta la proprietà One Shot su "On".

Ora aggiungi questo script a ''HUD'':

extends CanvasLayer

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

We now want to display a message temporarily, such as "Get Ready", so we add the following code

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

We also need to process what happens when the player loses. The code below will show "Game Over" for 2 seconds, then return to the title screen and, after a brief pause, show the "Start" button.

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()

Questa funzione viene chiamata quando il giocatore perde. Mostra "Game Over" per 2 secondi, poi ritorna alla schermata del titolo e, dopo una breve pausa, mostra il pulsante "Start".

Nota

Quando è necessario sospendere per un breve periodo di tempo, un'alternativa all'utilizzo di un nodo Timer consiste nell'utilizzare la funzione create_timer() di SceneTree. Questo può essere molto utile per ritardare, come nel codice sopra, dove vogliamo aspettare un po 'di tempo prima di mostrare il pulsante "Start".

Add the code below to HUD to update the score

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

Connect the timeout() signal of MessageTimer and the pressed() signal of StartButton, and add the following code to the new functions:

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

func _on_message_timer_timeout():
    $Message.hide()

Collegamento di HUD a Main

Ora che abbiamo finito di creare la scena HUD, tornare a Main. Istanza la scena HUD in Main come hai fatto per la scena Player. L'albero della scena completo dovrebbe essere simile a questo, quindi assicurati di non aver tralasciato nulla:

../../_images/completed_main_scene.webp

Ora dobbiamo collegare la funzionalità HUD al nostro script Main. Ciò richiede alcune aggiunte alla scena Main:

In the Node tab, connect the HUD's start_game signal to the new_game() function of the Main node by clicking the "Pick" button in the "Connect a Signal" window and selecting the new_game() method or type "new_game" below "Receiver Method" in the window. Verify that the green connection icon now appears next to func new_game() in the script.

In new_game(), aggiorna la visualizzazione del punteggio e mostra il messaggio "Get Ready":

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

In game_over() dobbiamo chiamare la corrispondente funzione HUD:

$HUD.show_game_over()

Finally, add this to _on_score_timer_timeout() to keep the display in sync with the changing score:

$HUD.update_score(score)

Avvertimento

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

Now you're ready to play! Click the "Play the Project" button. You will be asked to select a main scene, so choose main.tscn.

Rimuovere i vecchi "creeps"

Se giochi fino al "Game Over" e inizi subito una nuova partita, i creeps del gioco precedente potrebbero essere ancora sullo schermo. Sarebbe meglio se scomparissero tutti all'inizio di una nuova partita. Abbiamo solo bisogno di un modo per dire a tutti i mob di sparire. Possiamo farlo con la funzione "gruppo".

Nella scena Mob, selezionare il nodo radice e cliccare sulla scheda "Nodo" accanto all'Inspector (lo stesso posto dove si trovano i segnali del nodo). Accanto a "Segnali", cliccare su "Gruppi" e si può digitare un nuovo nome per il gruppo e cliccare su "Aggiungi".

../../_images/group_tab.webp

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")

La funzione call_group() chiama la funzione cosi denominata su ogni nodo di un gruppo - cosi facendo diciamo ad ogni mob di cancellarsi.

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.