Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Pantalla frontal

La pieza final que necesita nuestro juego es una interfaz de usuario (IU) para mostrar elementos como la puntuación, un mensaje de "game over" y un botón de reinicio.

Crea una nueva escena y añade un nodo CanvasLayer llamado HUD. "HUD" son las siglas de "heads-up display", una pantalla informativa que aparece superpuesta a la vista del juego.

El nodo CanvasLayer nos permitirá colocar elementos de nuestra UI en una capa por encima del juego, así la información que mostrará no estará cubierta por ningún elemento como el jugador o los enemigos.

El HUD necesitará mostrar la siguiente información:

  • Puntuación, cambiado por ScoreTimer.

  • Un mensaje como "Game Over" o "Get Ready!"

  • Un botón "Start" para comenzar el juego.

El nodo básico para elementos de UI es Control. Para crear nuestra UI, usaremos dos tipos de nodos Control: Label y Button.

Cree los siguientes hijos del nodo HUD:

  • Label llamado ScoreLabel.

  • Label llamado Message.

  • Button llamado StartButton.

  • Timer llamado MessageTimer.

Haz clic en ScoreLabel y escribe un número en el campo Text del inspector. La fuente por defecto para los nodos Control es pequeña y no escala bien. En los recursos del juego se incluye una fuente llamada "Xolonium-Regular.ttf". Para usar esta fuente, haz lo siguiente:

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.

Message

  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.

En el MessageTimer, ajusta el Wait Time en 2 y la propiedad One Shot en "Activado".

Ahora agrega este 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\nCreeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    await get_tree().create_timer(1.0).timeout
    $StartButton.show()

Esta función se llamará cuando el jugador pierde. Mostrará "Game Over" durante 2 segundos, luego volverá a la pantalla de título y revelará el botón "Start".

Nota

Cuando necesite hacer una pausa por un breve tiempo, una alternativa al uso de un nodo temporizador es usar la función create_timer() del árbol de escena. Esto puede ser muy útil para retrasar, como en el código anterior, donde queremos esperar un poco de tiempo antes de mostrar el botón "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()

Conectando HUD a Main

Ahora que hemos terminado de crear la escena del HUD, regresa a Main. Instancia la escena HUD en Main como hiciste con la escena de Player. El árbol de la escena debe verse así, asegúrate que no te olvidaste de nada:

../../_images/completed_main_scene.webp

Ahora conectaremos la funcionalidad de HUD a nuestro script Main. Esto requiere unas pocas adiciones a la escena 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.

Remember to remove the call to new_game() from _ready().

En``new_game()``, actualiza la puntuación y muestra el mensaje "Get Ready":

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

En game_over() necesitaremos llamar la función correspondiente en HUD:

$HUD.show_game_over()

Just a reminder: we don't want to start the new game automatically, so remove the call to new_game() in _ready() if you haven't yet.

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

$HUD.update_score(score)

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.

Removiendo los viejos "creeps"

Si juegas hasta el "Game Over" y comienzas un juego nuevo, los "creeps" del juego previo estarán todavía en pantalla. Sería mejor si todos desaparecen al comienzo del juego nuevo. Sólo necesitamos decirle a todos los enemigos que se remuevan solos. Podemos hacer esto con la característica de "grupos".

En la escena Mob, selecciona el nodo raíz y haz clic en la pestaña "Node" junto al Inspector (el mismo lugar donde encuentras las señales del nodo). Al lado de "Señales", haz clic en "Grupos" y puedes escribir un nuevo nombre de grupo y hacer clic en "Añadir".

../../_images/group_tab.webp

Ahora todos los enemigos estarán en el grupo "mobs". Podremos entonces agregar la siguiente línea a la función new_game() en Main:

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

La función call_group() llama a la función nombrada en cada nodo de un grupo - en este caso le estamos diciendo a cada grupo que se elimine a sí mismo.

El juego está casi terminado en este punto. En la siguiente y última parte, lo puliremos un poco agregando un fondo, música en bucle y algunos atajos de teclado.