Ich hoffe, Sie haben es satt, auf den zweiten Teil des Artikels zu warten, der sich mit Aspekten der Spieleentwicklung unter Verwendung der Godot Engine am Beispiel des Spiels Like Coins befasst. Auf der Tagesordnung steht viel von allem, was „lecker“ und „gesund“ ist. Machen Sie sofort eine Reservierung, dass wir in diesem Artikel das zuvor gestartete Spiel abschließen, dessen Anfang Sie hier lesen können - Erstellen des Spiels "Like Coins" auf der Godot Engine. Teil 1 , aber die Artikelserie wird fortgesetzt, weil Es gab so viel Material, dass ich einen Teil davon beiseite gelegt habe, aber wir werden auf jeden Fall später darauf zurückkommen. Lass den "Gamedev" beginnen!
Szene "Main"
Im vorherigen Teil des Artikels haben wir auf der Hauptbühne ( Main
) angehalten und werden wahrscheinlich damit fortfahren. Wir löschen alles, was zuvor hinzugefügt wurde (wenn Sie natürlich etwas hinzugefügt haben, um zu überprüfen, wie alles funktioniert). Wenn nichts in die Szene geladen wurde, sollten wir Node
hinzufügen, das wiederum das übergeordnete Element für die unten aufgeführten Knoten ist sollte auch zur Szene hinzugefügt werden:
ColorRect
("Hintergrund") - Füllen Sie die Hintergrundfarbe aus.
Player
- das "Player" -Objekt (Ich hoffe, Sie sind nicht verwirrt, weil ich die Player
Szene als Objekt bezeichne?);
Node
("Container") - "Container" zur vorübergehenden Aufbewahrung von Münzen;
Position2D
("PlayerStart") - legt zu Beginn des Spiels die Anfangsposition des "Player" -Objekts fest;
Timer
("GameTimer") - Zeitlimitzähler;
Wählen Sie ColorRect
und wählen ColorRect
in der Symbolleiste: Layout -> Full Rect
, um es auf den gesamten Bereich des Bildschirms ColorRect
(in Zukunft wird häufig auf diese Funktion zurückgegriffen, daher empfehle ich Ihnen, andere in der Layout
angegebene Vorgänge Layout
zu studieren). Geben Sie in der Eigenschaft "Farbe" die gewünschte Füllfarbe an. Mit TextureRect
können Sie dasselbe TextureRect
. Statt zu füllen, müssen Sie das Bild über die Eigenschaft "Texture" laden. Position2D
für Position2D
in der Eigenschaft "position" die Werte "x" und "y" an - dies dient als Ausgangsposition für den Player
. Natürlich können Sie mit Hilfe des Skripts die Positionierungswerte direkt im Player
selbst festlegen, aber wir lernen nicht nur, Spiele zu entwickeln, sondern lernen auch "Godot", sodass es nicht überflüssig ist, verschiedene Optionen zur Lösung eines Problems in Betracht zu ziehen.
Skript für "Main"
Fügen Sie ein Skript für Node
und drucken Sie Folgendes:
extends Node
Die Eigenschaften "Münze" und "Spielzeit" werden im Inspector
angezeigt. Ziehen Sie die Szene "Coin.tscn" auf die Eigenschaft "Coin" und setzen Sie "Playtime" auf "40" (die Dauer des Spiels in Sekunden).
Wenn das Spiel beginnt, sollte jedes Mal eine Initialisierung stattfinden - Vorbereitung auf die Arbeit, Bestimmung der erforderlichen Parameter für einen qualitativ hochwertigen und fehlerfreien Betrieb der Anwendung. Dies ist ein obligatorischer Schritt, daher sollten Sie sich zuerst darum kümmern.
func _ready(): randomize()
Beachten Sie, dass bei der Angabe des Namens des Player
Objekts das Symbol "$" verwendet wird. Dies ist "syntaktischer Zucker", mit dem Sie direkt auf den Knoten in der aktuellen Szene zugreifen können. Dies ist eine gute Alternative zur get_node("Node1")
(obwohl die Verwendung des letzteren nicht verboten ist). Wenn "Node1" einen Nachkommen von "Node2" hat, können Sie auch diese Methode verwenden - $Node1/Node2
. Beachten Sie, dass das automatische Ausfüllen in Godot hervorragend funktioniert. Vernachlässigen Sie es also nicht. Die Verwendung eines Leerzeichens in den Namen der Knoten ist unerwünscht, aber immer noch gültig. Verwenden Sie in diesem Fall Anführungszeichen - $"My best Node1"
.
Neues Spiel
Um ein neues Spiel zu starten, bestimmen wir die entsprechende Funktion dafür, die wir dann beispielsweise per Knopfdruck aufrufen können.
func new_game(): playing = true
Die Funktion "start ()" mit dem Argument $PlayerStart.position
den Spieler an den Startort, und die Funktion "spawn_coins ()" ist, wie Sie sich vorstellen können, für das Spawn von Münzen auf dem Spielfeld verantwortlich.
func spawn_coins(): for i in range(4 + level): var c = Coin.instance() $CoinContainer.add_child(c) c.window_size = window_size c.position = Vector2(rand_range(0, window_size.x), rand_range(0, window_size.y))
Die range(4 + level)
gibt ein Array mit einem bestimmten Bereich zurück, dessen Wert gleich der Summe aus der Anzahl der Münzen und dem Wert der aktuellen Stufe ist. Ein Bereich kann ein Argument enthalten, wie in unserem Fall entweder zwei Argumente oder drei Argumente (das dritte Argument ist ein Array-Schritt). In dieser Funktion erstellen wir mehrere Instanzen des Objekts „Coin“ und fügen CoinContainer
als CoinContainer
Elemente hinzu (ich hoffe, Sie haben nicht vergessen, dass wir dank PackedScene
bereits Zugriff auf das Objekt PackedScene
). Denken Sie daran, dass jedes Mal, wenn Sie eine Instanz eines neuen Knotens erstellen (die instance()
-Methode), diese mit add_child()
zum Baum hinzugefügt werden muss. Als nächstes legen wir den Bereich für einen möglichen Laich von Münzen fest, damit diese nicht versehentlich hinter dem Bildschirm erscheinen, und weisen dann zufällig eine Position zu. Die letzte Zeile sieht nicht wenig ästhetisch aus, daher schlage ich vor, sie zu vereinfachen, indem ich auf den Singleton zurückgreife.
Singleton
Der zweite Vorname des Singleton lautet "Startup". Schon suggestiv, oder? Ich sage Ihnen, ein Singleton funktioniert wie folgt: Ein Skript, in das wir alles schreiben können, was wir wollen (angefangen beim Deklarieren von Variablen bis hin zum "Wechseln" von Szenen, einschließlich Laden und Entladen), wird zuerst geladen, wobei die Anwendung ausgeführt wird, und auf alle Inhalte kann von jedem zugegriffen werden Projektpunkte. In gewisser Weise ist dies eine Art benutzerdefiniertes globales Repository für „alles“, das zu einem bestimmten Zeitpunkt verfügbar ist.
Beachten Sie, dass das Projekt über ein eigenes globales Repository verfügt, dessen Inhalt wir auch verwenden können. Sie können mit ProjectSettings.get_setting(name)
zugreifen, wobei name
der Name des erforderlichen Parameters ist.
Um nun etwas aus dem Repository "_G" zu verwenden, reicht es aus, es beim Namen aufzurufen und dann die aufzurufende Methode oder was auch immer wir dort haben, anzugeben. Erstellen Sie also ein leeres Skript und schreiben Sie die unten angegebene Funktion hinein:
extends Node func rand(): var rrand = Vector2(rand_range(40, 760), rand_range(40, 540)) return rrand

Speichern Sie es anschließend und gehen Sie zu den Projekteinstellungen: Project -> Project Settings -> AutoLoad
. Wir wählen unser neu erstelltes Skript aus, legen einen Namen dafür fest, z. B. "_G", und kehren zur Funktion "spawn_coins ()" zurück, um die Frist geringfügig anzupassen und durch den folgenden Code zu ersetzen:
... c.position = _G.rand()
Jetzt lohnt es sich zu überprüfen, was passiert ist, indem Sie "spawn_coins ()" in den Block "_ready ()" setzen und die Anwendung auf F5 ausführen. Und vergessen Sie nicht, Main.tscn
als Main.tscn
auszuwählen. Main.tscn
Sie aus irgendeinem Grund einen Fehler bei der Auswahl gemacht haben, können Sie die Main.tscn
manuell ändern. Dazu müssen Sie zu den Projekteinstellungen gehen: General -> Run -> MainScene
. Funktioniert es Dann mach weiter.
Wie viele Münzen sind noch übrig?
Fahren wir fort. Als nächstes müssen Sie überprüfen, wie viele Münzen noch übrig sind, um den Spieler auf das nächste Level zu bringen, ihm einen kleinen „Bonus“ in Form einer Verlängerung der Zeit um 5 Sekunden geben und die Münzen dann erneut spawnen.
func _process(delta):
Benutzeroberfläche
Unsere gesamte Benutzeroberfläche besteht aus den folgenden Elementen: Punkteanzeige, aktuelles Level, Uhrzeit, Name des Spiels und eine Schaltfläche, die den Start des Spiels auslöst. Erstellen Sie eine Szene ( HUD.tscn
) mit einem übergeordneten CanvasLayer
(ermöglicht das Zeichnen einer Benutzeroberfläche über dem Spielfeld). Mit Blick auf die Zukunft werde ich sagen, dass es nicht sehr bequem ist, Elemente der Benutzeroberfläche zu verwalten, zumindest für mich, aber eine ziemlich breite Liste von Elementen und eine aktive Entwicklung sorgen in der glänzenden Zukunft für eine positive Stimmung für die Entwicklung dieses Aspekts der Engine.

In Godot gibt es sogenannte "Steuerknoten", mit denen Sie untergeordnete Elemente in Bezug auf die angegebenen Parameter des übergeordneten Elements automatisch formatieren können. Jeder Typ von "Steuerknoten" verfügt über spezielle Eigenschaften, die steuern, wie sie den Standort ihrer Nachkommen steuern. Ein lebhafter Vertreter dieses Typs ist MarginContainer
, der der Szene hinzugefügt werden muss. Mit Hilfe von Layout -> Top Wide
strecken Layout -> Top Wide
es oben im Fenster und geben in den Eigenschaften dieses Objekts im Abschnitt Rand die Einrückungen an den Kanten an: links, oben und rechts. MarginContainer
sollte drei MarginContainer
Label
mit den folgenden Namen haben: ScoreLabel
, LevelLabel
und TimeLabel
. Fügen Sie sie der Szene hinzu. Align
Eigenschaft Ausrichten nach links, in der Mitte und rechts aus. Es bleibt noch ein weiteres Label
( Messagelabel
) Messagelabel
, das in der Mitte platziert wird, alles auch mit Hilfe von Layout
, und die Schaltfläche ( StartButton
) etwas tiefer platziert.

Lassen Sie uns nun die Benutzeroberfläche ansprechbar machen. Wir müssen die Zeit und die Anzahl der gesammelten Münzen aktualisieren und das aktuelle Level hervorheben. Fügen Sie ein Skript für den HUD
Knoten hinzu.
extends CanvasLayer signal start_game func update_score(value): $MarginContainer/ScoreLabel.text = str(value) func update_level(value): if len(str(value)) == 1: $MarginContainer/TimeLabel.text = "0: 0" + str(value) else: $MarginContainer/TimeLabel.text = "0: " + str(value) func update_timer(value): $MarginContainer/TimeLabel.txt = str(value)
Für MessageLabel
benötigen wir einen Timer, um den Text der Nachricht für kurze Zeit zu ändern. Fügen Sie einen Timer
Knoten hinzu und ersetzen Sie seinen Namen durch MessageTimer
. Stellen Sie im Inspektor die Wartezeit auf 2 Sekunden ein und aktivieren Sie das Kontrollkästchen im Feld One Shot
. Dies stellt sicher, dass der Timer beim Start nur einmal ausgeführt wird.
func show_message(text): $MessageLabel.text = text $MessageLabel.show() $MessageTimer.start()
Verbinden Sie das timeout()
-Signal mit "MessageTimer" und fügen Sie Folgendes hinzu:
func _on_MessageTimer_timeout(): $MessageLabel.hide()
Verbinden Sie auf der Registerkarte "Node" für StartButton
das Signal pressed()
. Wenn Sie auf die Schaltfläche StartButton
klicken StartButton
sollte diese zusammen mit MessageLabel
verschwinden und dann ein Signal an die StartButton
senden, wo wir sie anschließend gleichzeitig erfolgreich abfangen, indem wir die auszuführende Funktion "new_game ()" verschieben. Wir implementieren dies mit dem folgenden Code. Vergessen Sie nicht, dass die Schaltfläche in der Text
Eigenschaft einen Textaufruf zum Starten des Spiels festlegt.
func _on_StartButton_pressed(): $StartButton.hide() $MessageLabel.hide() emit_signal("start_game")
Um mit der Benutzeroberfläche fertig zu werden, schreiben wir die letzte, letzte Funktion - die Funktion, eine Nachricht über das Ende des Spiels anzuzeigen. In dieser Funktion muss die Beschriftung "Game Over" nicht länger als zwei Sekunden angezeigt werden und dann verschwinden, was dank der Funktion "show_message ()" möglich ist. Sie müssen jedoch erneut die Startschaltfläche eines neuen Spiels anzeigen, sobald eine Meldung angezeigt wird, dass das Spiel beendet ist. yield()
MessageTimer
die Ausführung der Funktion, bis ein Signal von MessageTimer
empfangen wird. MessageTimer
ein Signal von MessageTimer
über seine Ausführung empfangen wird, setzt die Funktion die Ausführung fort und bringt uns in ihren ursprünglichen Zustand zurück, damit wir ein neues Spiel erneut starten können.
func show_game_over(): show_message("Game Over") yield($MessageTimer, "timeout") $StartButton.show() $MessageLabel.text = "LIKE COINS!" $MessageLabel.show()
Ende?
Lassen Sie uns das Feedback zwischen dem HUD
und Main
einrichten. Fügen Sie die HUD
Szene zur GameTimer
und verbinden Sie das GameTimer
Signal über GameTimer
timeout()
in der GameTimer
indem Sie Folgendes hinzufügen:
func _on_GameTimer_timeout(): time_left -= 1
Verbinden Sie dann die Signale pickup()
und die()
des Players.
func _on_Player_pickup(): score += 1 $HUD.update_score(score) func _on_Player_die(): game_over()
Am Ende des Spiels sollten einige weitere Dinge passieren, die nicht übersehen werden sollten. Schreiben Sie den folgenden Code, und ich werde erklären.
func game_over(): playing = false $GameTimer.stop() for coin in $CoinContainer.get_children(): coin.queue_free() $HUD.show_game_over() $Player.die()
Diese Funktion stoppt das Spiel und die verbleibenden Münzen werden show_game_over()
und die verbleibenden Münzen werden show_game_over()
. Anschließend wird show_game_over()
für das HUD
aufgerufen. Der nächste Schritt besteht darin, die Animation zu starten und den Prozess der Ausführung des Player
Knotens zu stoppen.
Schließlich müssen Sie StartButton
aktivieren, das mit der Funktion new_game()
verbunden sein muss. Klicken Sie auf den HUD
Knoten und klicken Make Function to Off
im Verbindungsdialogfeld auf Funktion new_game
(dies verhindert die Erstellung einer neuen Funktion). new_game
Feld Method In Node
den Namen der verbundenen Funktion an - new_game
. Dadurch wird das Signal mit einer vorhandenen Funktion verbunden und keine neue erstellt.
Der letzte Schliff besteht darin, new_game()
aus der Funktion _ready()
zu entfernen und der Funktion _ready()
die folgenden zwei Zeilen new_game()
:
... $HUD.update_score(score) $HUD.update_timer(time_left)
Jetzt können wir mit Zuversicht sagen, dass das Spiel fertig ist, jetzt ist es ziemlich "spielbar", aber ohne Effekte. Letzteres werden wir im nächsten Artikel betrachten und verschiedenen „Dekorationen“ große Aufmerksamkeit widmen, um das Gameplay zu diversifizieren und die Möglichkeiten von „Godot“ weiter zu erkunden. Vergessen Sie daher nicht, die Veröffentlichung der Artikel zu befolgen. Viel Glück!