Up to date

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

Head-up-Display

Das Letzte, was unser Spiel noch benötigt, ist eine Benutzeroberfläche (User Interface, UI) um Dinge anzuzeigen wie die Punktzahl, ein "Game Over"-Text und einen Neustart-Button.

Erstellen Sie eine neue Szene, klicken Sie den "Anderer Node"-Button und fügen Sie einen CanvasLayer-Node mit dem Namen HUD hinzu. "HUD" steht für "Head-up-Display", eine Informationsanzeige, die als Overlay über der Spielansicht erscheint.

Mit dem CanvasLayer-Node können wir unsere UI-Elemente auf einer Ebene über dem Rest des Spiels zeichnen, so dass die angezeigten Informationen nicht durch irgendwelche Spielelemente wie den Spieler oder Mobs verdeckt werden.

Das HUD sollte die folgenden Informationen anzeigen:

  • Die Punktzahl, geändert durch ScoreTimer.

  • Eine Nachricht, wie z.B. "Game Over" oder "Get Ready!"

  • Einen "Start"-Button, um das Spiel zu starten.

Der Basis-Node für UI-Elemente ist Control. Um unsere Benutzeroberfläche zu erstellen, verwenden wir zwei Arten vom Control-Nodes: Label und Button.

Erstellen Sie das folgenden Nodes als Child-Objekte des HUD-Nodes:

  • Label genannt ScoreLabel.

  • Label genannt Message.

  • Button genannt StartButton.

  • Timer genannt MessageTimer.

Klicken Sie auf das ScoreLabel und geben eine Zahl in das Text-Feld im Inspektor ein. Die Default-Schriftart für Control-Nodes ist klein und lässt sich nicht gut skalieren. In den Spiel-Assets ist eine Schriftdatei namens "Xolonium-Regular.ttf" enthalten. Um diese Schriftart zu verwenden, gehen Sie wie folgt vor:

Wählen Sie unter "Theme-Überschreibungen > Schriftarten" "Laden" und wählen Sie die Datei "Xolonium-Regular.ttf".

../../_images/custom_font_load_font.webp

Wenn die Schriftgröße immer noch zu klein ist, erhöhen Sie sie unter "Theme-Überschreibungen> Schriftgrößen" auf 64. Wenn Sie dies mit dem ScoreLabel gemacht haben, wiederholen Sie die Änderungen für die Nodes Message und StartButton.

../../_images/custom_font_size.webp

Bemerkung

Anker: Control-Nodes haben eine Position und eine Größe, aber sie haben auch Anker. Anker definieren den Ursprung - den Referenzpunkt für die Ränder des Nodes.

Ordnen Sie die Nodes wie unten gezeigt an. Sie können die Nodes ziehen, um sie manuell zu platzieren, oder für eine genauere Platzierung die "Anker-Vorgaben" verwenden.

../../_images/ui_anchor.webp

ScoreLabel

  1. Fügen Sie den Text 0 hinzu.

  2. Setzen Sie die "Horizontale Ausrichtung" und "Vertikale Ausrichtung" auf Mitte.

  3. Wählen Sie die "Anker-Vorgabe" Mitte oben.

Nachricht

  1. Fügen Sie den Text Dodge the Creeps! hinzu.

  2. Setzen Sie die "Horizontale Ausrichtung" und "Vertikale Ausrichtung" auf Mitte.

  3. Setzen Sie den "Autowrap-Modus" auf Wort, sonst bleibt das Label in einer Zeile.

  4. Unter "Control - Layout/Transformation" setzen Sie "Größe X" auf 480, um die gesamte Breite des Bildschirms zu nutzen.

  5. Wählen Sie die "Anker-Vorgabe" Mitte.

StartButton

  1. Fügen Sie den Text Start hinzu.

  2. Unter "Control - Layout/Transformation" setzen Sie "Größe X" auf 200 und "Größe Y" auf 100, um ein wenig mehr Abstand zwischen dem Rahmen und dem Text zu schaffen.

  3. Wählen Sie die "Anker-Vorgabe" Mitte unten.

  4. Unter "Control - Layout/Transformation" setzen Sie "Position Y" auf 580.

Stellen Sie im MessageTimer die Wartezeit auf 2 und stellen Sie die Einmalig Eigenschaft auf "An".

Fügen Sie nun dieses Skript zu HUD hinzu:

extends CanvasLayer

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

Wir möchten nun vorübergehend eine Meldung anzeigen, z.B. "Get Ready", also fügen wir folgenden Code ein

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

Wir müssen auch verarbeiten, was passiert, wenn der Spieler verliert. Der folgende Code zeigt 2 Sekunden lang "Game Over" an, kehrt dann zum Titelbildschirm zurück und zeigt nach einer kurzen Pause den "Start"-Button an.

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

Diese Funktion wird aufgerufen, wenn der Spieler verliert. "Game Over" wird für 2 Sekunden angezeigt und wechselt dann zum Titelbildschirm. Nach einer kurzen Pause wird die "Start"-Button angezeigt.

Bemerkung

Falls eine kurze Pause benötigt wird, kann als Alternative zum Timer-Node die Funktion create_timer() von SceneTree verwendet werden. Das kann sehr nützlich sein, um eine Verzögerung hinzuzufügen. Wie im obigen Code, wo wir ein wenig warten wollen, bevor der "Start"-Button angezeigt wird.

Fügen Sie den folgenden Code in HUD ein, um den Spielstand zu aktualisieren

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

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

Das HUD mit Main verbinden

Jetzt, da wir die HUD-Szene erstellt haben, gehen Sie zurück zu Main und platzieren Sie die HUD-Szene in Main genauso wie die Player-Szene. Der gesamte Szenenbaum sollte so aussehen, also stellen Sie sicher, dass nichts fehlt:

../../_images/completed_main_scene.webp

Nun müssen wir die HUD-Funktionalität mit unserem Main-Skript verbinden. Dies erfordert einige Ergänzungen in der Main-Szene:

Verbinden Sie auf dem "Node"-Tab das Signal start_game des HUD mit der Funktion new_game() des Main-Nodes, indem Sie im Fenster "ein Signal verbinden" auf den "Auswählen"-Button klicken und die Methode new_game() auswählen oder im Fenster unter "Empfänger-Methode" "new_game" eingeben. Vergewissern Sie sich, dass das grüne Verbindungs-Icon nun neben func new_game() im Skript erscheint.

Aktualisieren Sie in new_game() die Punkteanzeige und zeigen Sie die Meldung "Get Ready" an:

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

In game_over() müssen wir die entsprechende HUD Funktion aufrufen:

$HUD.show_game_over()

Schließlich fügen Sie dies zu _on_score_timer_timeout() hinzu, um die Anzeige mit dem sich ändernden Spielstand zu synchronisieren:

$HUD.update_score(score)

Warnung

Vergessen Sie nicht, den Aufruf von new_game() aus _ready() zu entfernen, falls Sie das nicht schon getan haben, sonst wird Ihr Spiel automatisch gestartet.

Jetzt können Sie spielen! Klicken Sie auf den "Projekt abspielen"-Button. Sie werden aufgefordert, eine Hauptszene auszuwählen, also wählen Sie main.tscn.

Alte Creeps entfernen

Wenn Sie bis zum "Game Over" spielen und dann ein neues Spiel starten, befinden sich die Creeps des vorherigen Spiel noch auf dem Bildschirm. Es wäre besser, wenn diese beim Start eines neuen Spiels verschwinden würden. Wir benötigen einen Weg um alle Mobs zu entfernen und dies geschieht mit dem "Gruppen"-Feature.

Wählen Sie in der Szene Mob den Root-Node und klicken Sie auf den "Node"-Tab neben dem Inspektor (die gleiche Stelle, an der Sie die Signale des Nodes finden). Klicken Sie neben "Signale" auf "Gruppen", und Sie können einen neuen Gruppennamen eingeben und auf "Hinzufügen" klicken.

../../_images/group_tab.webp

Nun sind alle Mobs in der Gruppe"mobs". Jetzt können wir folgende Zeile zur Funktion new_game() in Main hinzufügen:

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

Die Funktion call_group() ruft die benannte Funktion für jeden Node in einer Gruppe auf - in diesem Fall sagen wir jedem Mob, dass er sich selbst löschen soll.

Das Spiel ist nun zum größten Teil fertig. Im nächsten und letzten Teil werden wir es etwas aufpolieren, indem wir einen Hintergrund, eine Musikschleife und einige Tastenkombinationen hinzufügen.