Monitor de alerta

A peça final que nosso jogo precisa é uma Interface de Usuário (UI) para exibir coisas como pontuação, uma mensagem de "game over" e um botão de reiniciar.

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.

O nó CanvasLayer nos permite desenhar nossos elementos de interface em uma camada acima do resto do jogo, de forma que as informações que ela mostrar não fiquem cobertas por quaisquer elementos do jogo, como o jogador ou os inimigos.

O HUD exibirá as seguintes informações:

  • Pontuação, alterado para ScoreTimer.

  • Uma mensagem, como "Game Over" ou "Prepare-se!"

  • Um botão "Iniciar" para começar o jogo.

O nó básico para elementos de interface é Control. Para criar nossa interface, usaremos dois tipos de nós Control: Label e Button.

Crie os seguintes itens como filhos do nó HUD:

  • Label nomeado ScoreLabel.

  • Label nomeado MessageLabel.

  • Button nomeado StartButton.

  • Timer nomeado MessageTimer.

Clique no ScoreLabel e digite um número no campo Text``no Inspetor. A fonte padrão para os nós ``Control é pequena e não escala bem. Há um arquivo de fonte incluído nos assets do jogo chamado "Xolonium-Regular.ttf". Para usar esta fonte, faça o seguinte para cada um dos três nós Control:

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

../../_images/custom_font_load_font.webp

O tamanho da fonte ainda está muito pequeno; aumente-o para 64 em "Theme Overrides > Font Sizes". Depois de fazer isso no nó ScoreLabel, repita as alterações nos nós Message e StartButton.

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

Organize os nós conforme mostrado abaixo. Você pode arrastar os nós para posicioná-los manualmente ou, para um posicionamento mais preciso, usar "Predefinições de âncora".

../../_images/ui_anchor.webp

ScoreLabel

  1. Adicione o texto 0.

  2. Defina o "Alinhamento Horizontal" e "Alinhamento Vertical" para Center.

  3. Escolha a "Predefinição de Âncora" Centro Superior.

Mensagem

  1. Add the text Dodge the Creeps!.

  2. Defina o "Alinhamento Horizontal" e "Alinhamento Vertical" para Center.

  3. Defina o "Modo Autowrap" para Word, caso contrário o rótulo permanecerá em uma linha.

  4. Na aba "Control - Layout - Transform", defina o parâmetro "X" de "Size" para 480 para usar toda a largura da tela.

  5. Escolha a "Predefinição de Âncora" Centro.

StartButton

  1. Adicione o texto: Iniciar.

  2. Em "Control - Layout - Transform", defina o parâmetro "X" de "Size" para 200 e "Y" de "Size" para 100, assim adicionando um pouco mais de espaço entre a borda e o texto.

  3. Escolha a "Predefinição de Âncora" Centro Inferior.

  4. Em "Control - Layout - Transform", defina "Y" de "Position" para 580.

No MessageTimer, defina o Wait Time (Tempo de Espera) para 2 e configure a propriedade One Shot (Apenas uma Vez) como "Ativo".

Agora, adicione este script ao HUD:

extends CanvasLayer

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

Agora queremos exibir uma mensagem temporária, como "Prepare-se", então vamos adicionar o seguinte código

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

Nota

Quando você precisa pausar por um breve tempo, uma alternativa ao do nó Timer é usar a função create_timer() do SceneTree. Isso pode ser muito útil para atrasar, como no código acima, onde queremos esperar um pouco de tempo antes de mostrar o botão "Iniciar".

Adicione o código abaixo no HUD para atualizar a pontuação

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

Connect the pressed() signal of StartButton and the timeout() signal of MessageTimer to the HUD node, 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 Principal

Agora que terminamos de criar a cena HUD, salve-a e volte para a Principal. Crie uma instância da cena HUD como fez com a cena Jogador, e coloque-a no final da árvore. A árvore completa deveria se parecer assim, então confira se não falta alguma coisa:

../../_images/completed_main_scene.webp

Agora precisamos conectar a funcionalidade de HUD ao roteiro de Principal. Isso exige algumas adições à cena Principal:

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.

Em new_game(), atualize o mostrador de pontuação e mostre a mensagem "Prepare-se":

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

Em game_over(), precisamos chamar a correspondente função de 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)

Aviso

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.

Removendo antigas criaturas

Se você jogar até o "Game Over" e iniciar um novo jogo, as criaturas do jogo anterior ainda poderão estar na tela. Seria melhor se todas elas desaparecessem no iníco de cada partida. Nós só precisamos de um jeito de falar para todos os inimigos se auto-destruirem. Nós podemos fazer isso com a funcionalidade "group"(grupo).

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

Dê o nome mobs ao grupo e clique em "ok" para adicionar um novo grupo de cena.

../../_images/add_group_dialog.webp

Agora todos os mobs estarão no grupo "mobs".

../../_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")

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.

O jogo está quase pronto nesse ponto. Na próxima e última parte, daremos um melhor acabamento adicionando um plano de fundo, música em "looping", e alguns atalhos de teclado.