Können wir auch Spiele entwickeln? Diese Frage stellten wir uns vor gut zwei Jahren. Auf unserem Tisch landete eine Anfrage zur Entwicklung eines Spiels, das 180 Minispiele mit einem didaktischen Hintergrund umfasst. Das Spiel soll sowohl auf iOS als auch auf Android gespielt werden können. Nachdem wir die Anforderungen an das Spiel geprüft hatten, entschieden wir uns, den Schritt in die Spieleentwicklung zu wagen. Wie wir dabei vorgegangen sind und was wir bisher gelernt haben, erfährst du in den nächsten Zeilen.
Zeit für eine Evaluation - Welche "Game Engine" ist die richtige?
Für die Entwicklung von Spielen stehen verschiedene 'Game Engines' zur Verfügung. Bei der Überprüfung der Anfrage haben wir uns die Engines Unity und Godot genauer angesehen. Mit beiden Engines können Spiele auf iOS und Android bereitgestellt werden. Wir haben uns schliesslich unter anderem aus folgenden Gründen für die Godot Engine entschieden:
- Eine dedizierte und robuste 2D-Engine.
- Open-Source mit einer aktiven Community.
- Der Build-Prozess kann über die Kommandozeile gesteuert werden, was eine kontinuierliche Integration und Bereitstellung mit einem CI-Server ermöglicht.
- Die Spiellogik kann mit GDScript (Python ähnlicher Syntax) erstellt werden.
Entwickeln mit Godot
Das zentrale Stück für die Entwicklung von Spielen mit Godot ist der Godot Editor. Mit diesem werden die Scripts, welche die Spiellogik enthalten, sowie alle Ressourcen organisiert, die für ein Spiel verwendet werden. Die Spiellogik wird mit der Scriptsprache GDScript direkt im Editor erstellt. Offiziell wird auch C# als Sprache für die Logik unterstützt. Im Gegensatz dazu ist der Unterbau in C++ geschrieben, was eine bessere Ausführungsgeschwindigkeit ermöglicht. Dieser Kern kann durch 'GD Extensions' erweitert werden, die ebenfalls in C++ geschrieben sind. Dank der Open-Source Natur ist es sogar möglich, die Engine direkt an individuelle Anforderungen anzupassen.
In Godot besteht ein Spiel aus Nodes, die in einer Baumstruktur angeordnet sind. Nodes sind quasi Bauteile, welche zusammen ein Spielobjekt, Level und schlussendlich den ganzen Spielablauf beschreiben. So kann zum Beispiel mit einem “Sprite2D” Node ein Bild dargestellt oder mit dem “AudioStreamPlayer” Node eine Audiodatei abgespielt werden.
Die Godot Engine stellt viele solcher Nodes mit den gängigsten Funktionen für die Spielentwicklung zur Verfügung. Reichen diese nicht aus, können mittels Vererbung eigene Node Typen erstellt werden. Neben der reinen Konfiguration kann ein Script an einen Node angehängt werden, um so unter anderem die Spiellogik zu schreiben. Während der Laufzeit erstellt die Godot Engine den sogenannten Scene Tree. In diesem werden Nodes hinzugefügt, angeordnet oder entfernt, um so das Spielgeschehen zu steuern. Beim Ein- und Austritt in den Scene Tree werden Funktionen in den Scripts der Nodes aufgerufen. Ein Script kann aber auch auf Ereignisse anderer Nodes, sogenannte Signals, reagieren, um Einfluss auf den Spielzustand zu nehmen.
Neben den Nodes gibt es ein anderes zentrales Bauteil, nämlich die Scenes. Eine Scene ist eine Aggregation von Nodes und kann bequem im Editor erstellt und konfiguriert werden. Die Scene Konfiguration wird in einer "tscn" Datei gespeichert und kann so in den Scripts geladen werden. Dadurch lassen sich wiederverwendbare Node-Kompositionen erstellen.
Die Godot Engine bietet noch viele weitere Funktionen, die jedoch den Rahmen dieses Eintrags sprengen würden. Daher darf ein Verweis auf die ausgezeichnete und ausführliche Dokumentation nicht fehlen.
GODOT – 2D und 3D plattformübergreifende Spiel-Engine
Godot Engine ist eine funktionsreiche Open-Source, plattformübergreifende Spiel-Engine zur Erstellung von 2D- und 3D-Spielen aus einer einheitlichen Benutzeroberfläche. Sie bietet eine umfassende Sammlung gängiger Werkzeuge, sodass Benutzer sich auf die Entwicklung von Spielen konzentrieren können, ohne das Rad neu erfinden zu müssen. Spiele können auf eine Vielzahl von Plattformen exportiert werden, darunter die wichtigsten Desktop-Plattformen (Linux, macOS, Windows), mobile Plattformen (Android, iOS) sowie webbasierte Plattformen und Konsolen.
Weitere Infos auf godotengine.org
Erkenntnisse aus der Entwicklung mit der Godot Engine
Es gibt nur wenige Vorgaben, wie die Scripte, Nodes und Scenes organisiert werden. Bei anderen Engines wie z.B Unity ist ein deutlich engeres Korsett vorgesehen. Am Anfang tauchten bei uns oft die Fragen auf: Was gehört in eine Scene? Welche Nodes benötigen ein Script? Wie können wir die mehrfach identische Logik wiederverwenden? Nach einiger Zeit haben wir uns immer mehr für einen Komponenten basierten Aufbau der Spiele und Elemente entschieden. Dabei lagern wir die Logik in einem Node aus und können diese in anderen Scenes 1:1 wiederverwenden. Die Objekte, welche dabei manipuliert werden, können mittels Script Variablen zugewiesen werden. Das erlaubt uns, eine Art generisches Script zu erstellen, welches die Logik für verschiedene Objekte bereitstellt.
Mit der zur Verfügung gestellten Scriptsprache GDScript, welche eine Python ähnliche Syntax hat, kann schnell einiges an Spiellogik und Effekten erstellt werden. Da es eine interpretierte Sprache ist, können Änderungen ohne Kompilierungs Schritt ausgeführt werden. Es ist sogar möglich, während der Laufzeit Programme per Hot Reload zu aktualisieren, was zum grossen Teil auch gut funktioniert. Obwohl die Sprache GDScript optional typisiert werden kann, ist die Typisierung nicht immer über alle Zweifel erhaben. Oft erlebten wir einen "Hä?" Moment so zum Beispiel bei den typisierten Arrays, welche während der Laufzeit Fehler produzierten, obwohl der Typ "korrekt" war.
Eine gute Sache ist, dass Godot komplett Open-Source ist. Die Projektverantwortlichen geben transparent Einblick in die aktuelle Entwicklung. Obwohl wir wegen der grossen Anzahl an Issues auf Github github.com/godotengine/godot/issues erschracken, sahen wir aber gleichzeitig auch viele Fehlerbehebungen und einen stetigen Ausbau der Engine. Dass der Quellcode zudem öffentlich einsehbar ist, ist ebenfalls ein grosser Vorteil. So konnten wir, als wir von einem Fehler betroffen waren, diesen im Quellcode lokalisieren und mittels einem Ticket und einem Pull Request die Fehlerbehebung in der darauffolgenden Version einbringen. In der Wartezeit auf die neue Version, haben wir eine Version mit der Fehlerbehebung kompiliert und konnten so schon ein Mini-Spiel umsetzen, welches ohne die Fehlerbehebung nicht wie erwartet funktioniert hätte.
Bereitstellung
Einer der zentralen Anforderungen an unser Projekt ist die Auslieferung des Spiels auf mehrere Plattformen, primär iOS und Android. Godot stellt dazu "Export Templates" zur Verfügung. Dies ermöglicht uns, das Spiel auf unseren Linux Maschinen zu entwickeln und das Ergebnis für die jeweilige Plattform bereitzustellen. Ok, ganz so einfach ist es nun auch nicht, für iOS braucht es doch noch ein Apple Gerät. Ein grosser Pluspunkt ist aber, dass die Export Funktionalität auch über eine Konsole ausgeführt werden kann. Daher lässt sich die Bereitstellung der Applikationen mit einem externen CI-Server, wie in unserem Fall mit Github Actions, realisieren. Am Ende ist also doch kein lokales Apple Gerät erforderlich…
Fazit
Die Godot Engine hat uns von der Funktionalität und der Flexibilität überzeugt. Die dedizierte 2D-Engine ersparte uns einiges an Komplexität und ermöglichte es uns, unsere ersten Mini-Spiele schon nach kurzer Zeit zu realisieren. Da Godot auch 3D unterstützt und die Struktur der Scenes und Nodes im 3D-Raum identisch ist, wäre die Hürde zur Entwicklung eines 3D-Spiels ebenfalls gering. Aufgrund der transparenten Entwicklung und der aktiven Community finden sich oft Lösungen bei Problemen. Obwohl GDScript nicht über alle Zweifel erhaben ist, lassen sich mit dieser Scriptsprache beeindruckende Spiele entwickeln. Gerne würde ich jedoch die C#-Variante ausprobieren, da diese Sprache insbesondere im Bereich der Polymorphie Funktionen wie zum Beispiel Interfaces bietet. Leider ist die Unterstützung von C# für den Export auf iOS und Android in der aktuellen Godot Version 4.2 immer noch experimentell, was einen Einsatz in unserem Projekt derzeit nicht zulässt. Aber wer weiss, vielleicht beim nächsten Spiel?