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, has click en "Otro Nodo" y agrega un nodo CanvasLayer llamado HUD. "HUD", que 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:

Dentro de "Theme Overrides > Fonts", elige "Load" y selecciona el archivo "Xolonium-Regular.ttf".

../../_images/custom_font_load_font.webp

El tamaño de la fuente aun es demasiado pequeño, increméntalo a 64 en "Theme Overrides > Font Sizes". Una vez lo hayas hecho con ScoreLabel, hazlo también para Message y StartButton.

../../_images/custom_font_size.webp

Nota

Anclas: Los nodos Control tienen posición y tamaño, pero también tienen anclas (anchor). Las anclas definen el origen - El punto de referencia para los bordes del nodo.

Acomoda los nodos como se muestra debajo. Puedes arrastrar y ubicarlos manualmente o, para un modo más preciso, utiliza "Anchor Presets".

../../_images/ui_anchor.webp

ScoreLabel

  1. Añade el texto 0.

  2. Ajuste la "Alineación horizontal" y la "Alineación vertical" a Center.

  3. Selecciona el "Anchor Preset" Center Top.

Message

  1. Agrega el texto Dodge the Creeps!.

  2. Ajuste la "Alineación horizontal" y la "Alineación vertical" a Center.

  3. Cambia el "Autowrap Mode" a Word, de otro modo el texto se mantendrá en una sola línea.

  4. Dentro de "Control - Layout/Transform" coloca "Size X" en 480 para usar todo el ancho de la pantalla.

  5. Elige el "Anchor Preset" Center.

StartButton

  1. Agrega el texto Start.

  2. Dentro de "Control - Layout/Transform", cambia "Size X" a 200 y "Size Y" a 100 para agregarle un poco de espacio entre el borde y el texto.

  3. Elige el "Anchor Preset" Center Bottom.

  4. Dentro de "Control - Layout/Transform", cambia "Position Y" a 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

Ahora queremos mostrar un mensaje temporalmente, como ej. "Get Ready" (Prepárate), así que agregaremos el siguiente código

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

También tenemos que procesar lo que sucede cuando el jugador pierde. El código siguiente mostrará "Game Over" durante 2 segundos, luego volverá a la pantalla de título y, después de una pequeña pausa, revelará el botón "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()

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

Agrega el siguiente código al HUD para actualizar la puntuación

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

Conecta la señal pressed()``de ``StartButton y la señal timeout() de MessageTimer al nodo HUD (interfaz), y agrega el siguiente código a las nuevas funciones:

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:

En la pestaña Nodo, conecta la señal start_game del HUD a la función new_game() del nodo Main haciendo clic en el botón "Seleccionar" en la ventana "Conectar una señal" y seleccionando new_game() o escribiendo "new_game" debajo de "Método del receptor" en la misma ventana. Verifica que el icono de conexión verde aparezca junto a func new_game() en el script.

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

Finalmente, agrega esto a _on_ScoreTimer_timeout() para mantener la interfaz en sincronía al cambiar la puntuación:

$HUD.update_score(score)

Advertencia

Cuando estés seguro de que todo funciona, quita la llamada a new_game() de ready() si no lo haz hecho todavía, de otro modo el juego iniciará automáticamente.

Now you're ready to play! Click the "Play the Project" button.

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

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" to open the group overview and the "+" button to open the "Create New Group" dialog.

../../_images/group_tab.webp

Name the group mobs and click "ok" to add a new scene group.

../../_images/add_group_dialog.webp

Now all mobs will be in the "mobs" group.

../../_images/scene_group_mobs.webp

We can then add the following line to the new_game() function in 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.