GameDevJS 2023
By André Jaenisch on 30.04.2023. About 9 minutes reading time. This text is estimated to be very confusing to understand.
Wie in den vergangenen Jahren habe ich auch dieses Jahr am GameDevJS 2023 teilgenommen. Dabei handelt es sich um einen Wettbewerb auf der Plattform itch.io, an den prinzipiell jeder teilnehmen kann. Ausgerichtet wird er von Andrzej Mazur, der auch js13kgames organisiert.
Jetzt stellt sich natürlich die Frage:
Warum sollte jemensch an einen Spiele-Wettbewerb teilnehmen?
Nun, dies hat verschiedene Gründe. Ich möchte diesen Blog-Beitrag dazu nutzen, meine Motivation auszulegen. Vielleicht kann ich ja auch andere motivieren, einmal etwas Zeit dafür zu organisieren?
It’s fun
Spiele sind ein Kulturgut. Sie erzählen viel von unserem Umgang miteinander. Das entscheidende Kriterium: Sie machen Spaß. Die Teilnahme daran ist freiwillig. Ansonsten ist es kein Spiel mehr.
Unser Leben ist so schon hart genug. In manchen Teilen der Welt mehr als in anderen. Etwas Zerstreuung und Miteinander ist da durchaus willkommen.
Zeitliche Begrenzung
Diese Wettbewerbe haben in der Regel eine zeitliche Begrenzung. Oftmals 24 bis 48 Stunden. Dies ist ausreichend, um etwas zusammenzustellen. Wenn denn die Zeit dafür bereitgestellt werden kann. Ich finde es als Familienvater eine ziemliche Herausforderung. Andrzej hingegen lässt mehr Spielraum. Dieser Jam hier etwa gewährt 13 Tage Zeit, um etwas zu entwickeln. Für mich war es bisher immer motivierend. Ich hatte nach meiner Erwerbstätigkeit Zeit, mich in das Projekt zu knien.
Was lerne ich daraus?
Ich nehme aus der Spiele-Entwicklung so einiges mit, was mir im professionellen Alltag zu Gute kommt.
Herausforderung angenommen
Als Webentwickler bin ich gefordert, zuverlässigen Code zu erstellen, der auch performant ist. Neben einer gewissen Industrie für Erwachsenenunterhaltung ist die Spiele-Industrie die Branche, welche die Grenzen von Programmen ausreizt. Ernsthaft, wenn ich nach Optimierungen suche, damit Code unter 60 FPS (Frames per Second, Bildwiederholungsrate) läuft, dann finde ich sehr viel Wissen in der Spieleindustrie. Fängt an von CPU-Optimierungen über Speicherverwaltung bis hin zu hochoptimierten Code.
Das hilft mir, mich mit der Programmiersprache selber zu beschäftigen, statt alles an Frameworks auszulagern, die für ein Millionenpublikum entwickelt wurden.
Research and Development
Ich habe die vergangenen Jahre dazu genutzt, mich nicht nur mit leichtgewichtigen JavaScript-Bibliotheken auseinander zu setzen. Diese konnte ich etwa dann in Bereichen einsetzen, die nicht nur JavaScript verwendeten (sei es Django oder PHP). Nein, ich habe auch mehr über SVG gelernt.
Die meisten Game Engines, welche ich in der Indie-Entwicklung sehe, setzen auf Canvas API. Dies ist gewissermaßen eine Zeichenfläche, auf die dann Pixel gemalt werden. Leider ist die Canvas-API komplett unzugänglich.
Mit meinem Hintergrund in Mathematik hat mich daher schon seit jeher die mathematische Grundlage hinter Vektorgrafiken angezogen. Hier andere Wege zu gehen hat nicht unbedingt zur Folge, dass ich Lehren aus der Canvas- Technologie nicht anwenden könnte. Ganz im Gegenteil. Ideen wie Sprites lassen sich durchaus übertragen.
Aber SVG bietet die Möglichkeit, auch Text-Repräsentationen wiederzugeben. Damit lassen sich auch Ausgabegeräte nutzen, die nicht an Menschen gerichtet sind, die über ein gutes Sehvermögen verfügen.
Find your niche
Interessanterweise fällt es mir leichter, meine Nische im Bereich der Spiele-Entwicklung zu definieren, als dass ich sie im Web-Bereich benennen könnte. Meine Spiele erlauben das Zusammenspielen mit anderen Menschen. Ich habe gelernt, wie ich dies über das Netzwerk realisiere, aber auch lokal an einem Gerät. Dabei möchte ich es aber nicht belassen. Stattdessen denke ich über Möglichkeiten nach, wie ich das Szepter aus der Hand geben kann und die Spieler ermutige, selber kreativ zu werden.
Zugegeben, die 13 Tage Entwicklungszeit reichen dafür nicht immer aus. Aber ich habe über verschiedene Jahre all die Puzzleteile zusammen getragen, die ich nur noch zusammenführen muss. Dies hat mich auch zur Erforschung einer Low-Code-Umgebung geführt (die auf die gleiche Architektur setzt wie die so entwickelten Spiele).
Jetzt ist es bei Zusammenspielen oftmals so, dass Latenz, also die Zeit zwischen Anfrage an und Antwort von einem System, eine kritische Bedeutung zukommt (Optimierung!). Ich löse das dadurch, dass meine Spiele in der Regel rundenbasiert sind. Ich mag selber nicht zu hektische Spiele spielen. Viel lieber genieße ich Spiele, die ein Nachdenken ermuntern oder gar einfordern.
Damit sind bei mir oftmals Puzzle- oder Logikspiele zu finden. Die Grafik ist dabei naturgegeben sehr geometrisch. Ich verwende Newton’sche Mechanik. Alles in 2D.
Ich belasse es aber nicht dabei, alles selber zu entwickeln. Das erfordert Wissen, welches ich nicht besitze. Dabei nutze ich aber auch die Gelegenheit, mir meine Abhängigkeiten sorgfältig auszuwählen. Bei Interesse erkläre ich auch gerne die mathematischen Hintergründe zu den Algorithmen, welche programmiert wurden. Denn leider ist es oftmals so, dass „ich den Code im Internet / Buch gefunden und abgeschrieben” habe.
Die Logik dahinter (etwa Matrizen-Algebra) habe ich in Eingangsvorlesungen von Mathematik gelernt. Damit kann ich meinen Beitrag zur Community leisten.
Does it scale?
Denn wenn ein Algorithmus verstanden wird, sind auch die Grenzen leichter zu verstehen. Wenn es auf Mathematik beruht, gibt es noch einen schönen Aspekt: Die Voraussetzungen sind wohldefiniert. Es ist nämlich so, dass Mathematik auf eine Handvoll Grundannahmen beruht (genannt Axiome) und sich alles andere daraus ableitet. Wenn jetzt bei einem Algorithmus die Voraussetzungen nicht erfüllt sind, lassen sich die Ergebnisse nicht garantiert. Ganz einfach.
In der numerischen Mathematik habe ich auch die Landau-Notation kennen gelernt. In der Informatik fällt das unter Big-O-Notation. Damit lassen sich Aussagen zur Effizienz von Algorithmen treffen. Etwa zur Abhängigkeit der Laufzeit von den Eingabedaten.
Nun gibt es auch Spiele, die sich an ein Millionenpublikum richten. Diese müssen so richtig effizient sein. Meine Spiele sind anders. Ich beschränke mich auf ein menschliches Level. Wenn ich mir Brettspiele so anschaue, dann sehe ich Spielerzahlen von höchstens einem halben Dutzend Menschen um einen Tisch herum. Damit habe ich mehr Spielraum, um auch ineffizienten Code schreiben zu dürfen. Ich nutze diesen, um den Code dafür verständlicher zu machen.
Playful learning
Mein Paradigma ist dabei sehr an Funktionaler Programmierung ausgerichtet. Dieses Jahr habe ich von Data-Oriented Programming erfahren, welches sich auch sehr nahe an dem spiegelt, was ich für mich als optimal ermittelt habe.
Dabei nehme ich eine Lektion von React und Redux und habe ein zentrales Objekt, welches den Zustand meines Spiels zu jedem beliebigen Zeitpunkt beinhaltet. Da ich nicht so viele bewegliche Teile in der Oberfläche habe, kann ich dabei ein einziges Objekt hernehmen.
Aus diesem Zustand leitet sich die Oberfläche ab. Aus Klassen-basiertem React nehme ich die Idee von Smart und Dumb Components. Die ersten haben dabei ein Verständnis von Zusammenhängen und kümmern sich um Interaktionen. Dumb Components interessiert das alles nicht. Sie bekommen einfach Eingaben und rendern diese auf den Bildschirm. Falls es interessante Ereignisse gibt, informieren sie die Vorfahren darüber.
Hier setze ich auf native Events, die vom Browser bereitgestellt werden.
Auch mein Wissen aus jQuery kommt mir hier zu gute, indem ich mich der
Event Delegation bediene. Ich habe ein einziges Element
(etwa <body>
), an dem ich Event Listener registriere. Da ich nicht zu einer
anderen Seite navigiere, muss ich mich auch nicht um Aufräumarbeiten kümmern.
Ankommende Events werden dabei dann analysiert und an die entsprechenden Handler weitergereicht, die sich um die Aktualisierung des States kümmern. Daraufhin wird die Oberfläche aktualisiert.
React ohne React. Sondern mit Funktionen und etwas Nachdenken. Damit bekomme ich die Ladezeiten auf einen Bereich herunter, den ich so bisher noch nicht mit Frameworks erreichen konnte (ich kann mir aber vorstellen, dass Svelte hier noch besser abschneiden könnte).
Artificial Intelligence
State-basierte Entwicklung hat aber auch noch weitere Vorzüge. Da ich mich darauf verlassen kann, dass sich die Oberfläche alleine aus dem Zustand ableitet, kann ich Berechnungen durchführen, ohne eine Oberfläche hinzuziehen zu müssen.
Durch das Heranziehen von Primitiven wie Object und Array kann ich auch die Daten analyiseren. Damit lassen sich etwa Methoden der Künstlichen Intelligenz und Fuzzing anwenden. Jetzt nicht die KI wie ChatGPT, sondern gewissermaßen Strategien, die basierend auf Daten Entscheidungen treffen sollen. Hier um einen Computer als Gegenspieler anbieten zu können, der für fehlende Mitspieler einspringen kann.
Aber auch das Prüfen von Extremwerten ist so einfacher. Ich brauche in der Regel kein überkompliziertes Setup. Durch die Funktionale Programmierung hantiere ich sowieso mit vielen kleinen Funktionen, die nur von ihren Eingabedaten abhängen.
Meine Sicherheitsbedenken beschränken sich auf die Handler, welche Nutzereingaben entgegennehmen (etwa ausgelöste Events) oder diese Ausgeben.
Ready Player Two?
Da ich mit Datenstrukturen arbeite, kann ich diese auch als JSON-Objekte über das Netzwerk verteilen. Hier verwende ich gerne socket.io. Prinzipiell würden aber auch andere Transport-Mechaniken (wie etwa WebRTC) funktionieren. JSON ist in vielen Programmiersprachen implementiert.
Wenn ich daraufhin Event-Handler registriere, die auf Mitteilungen reagieren und diese zum Aktualisieren des lokalen States verwenden, dann ist die Architektur schnell in der Lage, auch über das Netzwerk zu agieren.
Bis zu ereignis-gesteuerter Architektur mit Kafka und Microservices ist es da nicht mehr weit. Auch Telemetrie wäre hier mit überschaubaren Aufwand machbar. Ich habe bisher aber noch nicht den Anwendungsfall gehabt.
Und wenn es sein muss, können auch bestimmte Objekte in ein NFT umgewandelt werden, wenn jemensch diese Abzocke gefällt. Ich kann dem nichts abgewinnen.
Tatsächlich möchte ich lieber die Möglichkeit geben, Kulturgüter zu bewahren. Für mich gehört dazu, den Quellcode zu teilen und die Möglichkeit zu geben, eigene Instanzen zu betreiben und die Spiele darauf einzustellen.
Denn es wäre doch schade, wenn nicht mehr gespielt werden kann, nur weil eine Firma meint, den Server dahinter abschalten zu müssen.
Dabei prägen Spiele uns Menschen so sehr.