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.

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.

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:

  1. Under Theme overrides > Fonts click on the empty box and select "New DynamicFont"

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

../../_images/custom_font2.png

Establezca la propiedad "Tamaño" dentro de Ajustes, 64 suele funcionar bien.

../../_images/custom_font3.png

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.

Nota

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.

Organiza los nodos como se muestra a continuación. Haz clic en el botón "Layout" para establecer la disposición de un nodo de Control:

../../_images/ui_anchor.png

Puedes arrastrar y ubicarlos manualmente o, para un modo más preciso, usa la siguiente configuración:

ScoreLabel

  • Layout: "Top Wide"

  • Text : 0

  • Align: "Center"

Message

  • Disposición : "HCenter Wide"

  • Text : Dodge the Creeps!

  • Align: "Center"

  • Envoltura Automatica : "Encendida"

StartButton

  • Text : Start

  • Disposición : "Center Bottom"

  • Margin:

    • Top: -200

    • Bottom: -100

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

Ahora agrega este script a HUD:

extends CanvasLayer

signal start_game

La señal start_game dirá al nodo Main que se ha presionado un botón.

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

Esta función se llamará cuando queramos mostrar un mensaje temporalmente, como "Get Ready".

func show_game_over():
    show_message("Game Over")
    # Wait until the MessageTimer has counted down.
    yield($MessageTimer, "timeout")

    $Message.text = "Dodge the\nCreeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    yield(get_tree().create_timer(1), "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".

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

Esta función será llamada por Main cada vez que el puntaje cambie.

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

func _on_StartButton_pressed():
    $StartButton.hide()
    emit_signal("start_game")

func _on_MessageTimer_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.png

Ahora conectaremos la funcionalidad de HUD a nuestro script Main. Esto requiere unas pocas adiciones a la escena Main:

En la pestaña Nodo, conecte la señal `` start_game '' del HUD a la función `` new_game () `` del nodo Principal escribiendo "new_game" en el "Método del receptor" en la ventana "Conectar una señal". Verifique que el icono de conexión verde ahora 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 _on_ScoreTimer_timeout() para mantener la interfaz en sincronía al cambiar la puntuación:

$HUD.update_score(score)

¡Ahora estás listo para jugar! Haz clic en el botón "Reproducir el proyecto". Se te pedirá que selecciones una escena principal, así que elige 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.png

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