Blitz Basic Script

Full Stack Webprojekt

22.10.2020 | Stefan Behrendt

Im Jahre 2020 ist der technologische State of the Art im Internet sehr fortgeschritten. Zahlreiche offizielle Standards bieten immer umfangreichere Möglichkeiten, mit verschiedenster Hardware auf allen erdenklichen Endgeräten im Netz zu surfen. Dabei ist es längst normal geworden, auf Kamera, Mikrofon, Grafikkarte und diverse Smartphone-Sensoren zuzugreifen und deren Fähigkeiten in Webanwendungen einzusetzen.

Wir möchten euch anhand eines Full Stack Webprojektes einmal zeigen, wie eine komplexe Webanwendung heutzutage aufgebaut ist. Das Projekt "BlitzBasicScript" bietet eine Plattform zur Entwicklung von Computerspielen direkt im Browser. Für ein authentisches Spielerlebnis ist es wichtig, moderne Grafik- und Soundeffekte einsetzen zu können und eine flüssige Darstellung zu erzielen. Wie das gelingt und welcher Tech-Stack dahinter steht, erfahrt ihr in diesem Blog-Beitrag.

Das Wichtigste zuerst

BlitzBasicScript

BlitzBasicScript ist ein webbasiertes Projekt mit dem Ziel, Computerspiele direkt im Webbrowser zu programmieren und zu spielen. Dabei kommen zahlreiche moderne Webtechnologien wie HTML5, Canvas, Web Audio und weitere zum Einsatz. Somit ist es möglich, nahezu ohne Einschränkungen die Leistung von CPU und Grafikkarte des Clients auszunutzen, um hochqualitative und performante 3D-Darstellungen zu berechnen und anzuzeigen.

Die Syntax der Skriptsprache basiert auf Blitz Basic und ist aufgrund ihrer Einfachheit speziell für die schnelle Entwicklung von Spielen geeignet. Leider wird Blitz Basic seit vielen Jahren nicht mehr weiter entwickelt, sodass die geschriebenen Programme auf aktuellen System nur eingeschränkt lauffähig und keinesfalls zukunftstauglich sind. Auf der anderen Seite gibt es derzeit quasi keine Programmiersprache für Computerspiele, welche ohne steile Lernkurve und umfangreiche Paradigmen daherkommt.

BlitzBasicScript soll diese Lücke füllen und moderne Technologien mit einfachen, etablierten Konzepten verbinden, um in erster Linie anfängerfreundlich zu sein.

Grundsätzlich kann man auf jedem elektronischen Gerät spielen, sofern ein Webbrowser installiert ist und eine Internetverbindung besteht.

Mono-Repository

Früher war es üblich, Software als großes Gesamtmodul (auch „Monolith“ genannt) zu entwickeln und zu veröffentlichen. Nachträgliche Anpassungen hatten dadurch immer Auswirkungen auf alle Teilsysteme zugleich. Deshalb werden heutzutage vorrangig so genannte „Micro Services“ entwickelt, um die starke Kopplung zwischen Komponenten zu lösen und eine bessere Wiederverwendbarkeit von Quellcode zu erreichen.

Während in der Regel jeder Micro Service sein eigenes Repository zur Code-Versionierung besitzt, setzen moderne Webprojekte inzwischen vermehrt auf ein „Mono-Repository“. Dabei werden alle Subsysteme in einem einzigen Repository eingecheckt, sodass für jedes Projekt die gleiche Codebasis zur Verfügung steht. Die Wiederverwendbarkeit von Quellcode wird dabei nochmals erhöht, da bei verteilten Repositories immer die Gefahr besteht, dass bei der Weiterentwicklung eines Micro Services die neue Version nicht mit allen Komponenten kompatibel ist und sich schwer durchschaubare Abhängigkeitsbäume ergeben.

Das Mono-Repository von BlitzBasicScript wurde mithilfe von nrwl/nx generiert. Es besteht im Wesentlichen aus drei Einheiten: Frontend (Angular), Backend (NestJS) und „Shared Libraries“, also gemeinsam genutzten TypeScript-Bibliotheken. Diese werden vor allem für die Kommunikation zwischen Front- und Backend via REST-API genutzt, aber auch für Klassen und Interfaces, die in beiden Systemen gleichermaßen zum Einsatz kommen.

Frontend

BlitzBasicScript ist eine interaktive Webanwendung, bei der die Eingabe durch den Programmierer bzw. Nutzer über eine Website erfolgt und die Ausführung der Befehle durch Services realisiert wird. Das Projekt wird gehostet unter https://www.blitzbasicscript.com.

Als Frontend-Framework kommt Angular zum Einsatz – aktuell in Version 10, wobei mit jedem Erscheinen einer neuen Major Version ein entsprechendes Upgrade durchgeführt wird. Angular ist eines der populärsten Web-Frontend-Frameworks und besteht aus komponentenbasierten Modulen sowie Services, welche per Dependency Injection leicht wiederverwendet werden können. Als Programmiersprachen kommen TypeScript für die Programmlogik, HTML5 für die Templates und SCSS-Layouts zum Einsatz.

Für die Umsetzung des Layouts und Designs wird die Style-Bibliothek Bulma genutzt. Dabei handelt es sich um ein quelloffenes CSS-Framework, welches komplett auf der CSS3-Layout-Methode FlexBox basiert und responsiv ist, also beliebige Geräte und Bildschirmauflösungen unterstützt. Bulma nutzt keine JavaScript-Effekte und kann deshalb ohne framework-spezifischen Wrapper direkt ins Frontend eingebunden werden. Es existieren zahlreiche freie, aber auch kostenpflichtige Themes, beispielsweise auf Bulmaswatch. BlitzBasicScript nutzt das kostenlose Theme „Superhero, welches einen dunklen Hintergrund und markante, kontrastreiche Vordergrundfarben in einem rechteckigen Layout präsentiert.

Unit-Tests werden mithilfe von Jest geschrieben. Dabei können einzelne Komponenten und Services in so genannten „Testbeds“ definiert und auf korrekte Methodenausführung geprüft werden. Externe Micro Services wie etwa eine REST-API können durch Mock-Objekte ersetzt werden, sodass keine Komponenten-Kopplung zwischen den einzelnen Unit-Tests entsteht. Zusätzlich bietet die „Code Coverage“ eine praktische Übersicht über die bereits getestete Codeabdeckung.

Backend

Das Backend von BlitzBasicScript ist verantwortlich für die Kommunikation des Frontends mit verschiedenen Datenbanken, welche etwa Nutzerdaten oder Befehlsdokumentationen enthalten. Als Grundlage dient eine umfangreiche REST-API mit Endpunkten für Dokumentation, Dateizugriff, Authentifizierung und viele weitere Themengebiete. Technisch gesehen ist das Backend nicht notwendig für die eigentliche Kompilierung und Ausführung von BlitzBasicScript-Programmen – wenn man von Lese- und Schreiboperationen absieht, die aufgrund des Sandbox-Modells des Webbrowsers nicht ohne weiteres erlaubt sind. Viel mehr lässt sich dadurch der Webauftritt des Projektes realisieren, in dem die Nutzer selbstständig Daten anlegen, verändern und löschen können.

Als Technologie zur Umsetzung des Backends setzen wir auf NestJS. Dieses Framework basiert auf node.js und ist für die Entwicklung effizienter, zuverlässiger und skalierbarer serverseitiger Anwendungen gedacht. Sowohl syntaktisch als auch in Bezug auf die eingesetzten Software-Design-Muster orientiert sich NestJS stark an Angular, weshalb sich der Einsatz beider Technologien in Kombination miteinander empfiehlt. Außerdem findet die Programmierung in TypeScript statt, ebenso wie auch im Frontend – man kann also geteilte Klassen und Interfaces leicht wiederverwenden. API-Endpunkte werden mithilfe von Controllern definiert, welche wiederum auf wiederverwendbare Services zugreifen.

Als Datenbank-Technologie wird auf die dokumentorientierte Apache CouchDB gesetzt und PouchDB als Backend-Interface genutzt, um vollständig JavaScript-kompatibel zu sein. Pro Service existiert eine eigene Datenbank: Somit gibt es jeweils einen zentralen Speicherort für Schlüsselwörter und Befehle, Nutzerdaten, Blogbeiträge, Codeprojekte und weiteres.

Graphics3D 1920, 1080

Global camera = CreateCamera()
Global light = CreateLight()
Global cube = CreateCube()
EntityColor(cube, 0, 255, 0)
PositionEntity(cube, 0, 0, 10)

MainLoop
  RenderWorld()
End MainLoop

Die Skriptsprache

BlitzBasicScript ist eine imperative Skriptsprache mit schwacher, dynamischer Typisierung. Sie orientiert sich in allen wesentlichen Konzepten an der mittlerweile veralteten Sprache Blitz Basic und versucht, deren Syntax und Semantik so weit wie möglich zu portieren. Blitz Basic selbst repräsentiert (wie der Name schon andeutet) einen BASIC-Dialekt, welcher um zahlreiche vordefinierte Befehle zur Kontrolle von 2D- und 3D-Grafik, Ein- und Ausgabe, Sound, Datenverwaltung und weitere Themenfelder ergänzt wurde. Es gibt nur eine „Core Library“, die alle Befehle bereits enthält und auch vollständig kompiliert, sodass die entstehenden Programme immer recht viel Speicherplatz verbrauchen.

Auch in BlitzBasicScript gibt es nur eine große Befehlssammlung, die nicht in kleinere Module unterteilt ist. Das hat den praktischen Effekt, dass keine Import-Statements vom Programmierer geschrieben werden müssen und man nicht erst lernen braucht, mit Modulen zu arbeiten. Stattdessen können Befehle direkt Zeile für Zeile mit ihren Parametern aufgerufen werden.

Das rechte Beispielprogramm initialisiert den 3D-Grafikmodus mit FullHD-Auflösung, erzeugt eine Kamera und eine Lichtquelle sowie einen Würfel, welche zuerst grün eingefärbt und dann um zehn Einheit in den Raum hinein verschoben wird. In der Hauptschleife (MainLoop) wird kontinuierlich das aktuelle 3D-Frame berechnet und auf den Bildschirm gezeichnet.

Game Engine

Als Game Engine für BlitzBasicScript kommt Babylon.js zum Einsatz. Die Software-Lizenz ist Open Source und das Projekt wird regelmäßig mit frischen Updates versorgt, sodass zukünftige 3D-Features zeitnah genutzt werden können.

Babylon.js kommt mit einem relativ simplen 3D-Welt-Modell daher, welches gut vergleichbar ist mit dem 3D-Ansatz von BlitzBasicScript. Daher ist es möglich, mit wenigen Codezeilen die BlitzBasicScript-Befehle 1:1 auf Babylon.js-Funktionen abzubilden. Wenngleich die Kontrolle gegenüber Low-Level-Frameworks wie Three.js eingeschränkt ist, wird grafisch trotzdem der State of the Art des im Browser technisch Möglichen erreicht.

Neben Standard-Features wie dem Laden und Erstellen von 3D-Modellen und Texturen gibt es in Babylon.js zahlreiche Möglichkeiten, visuelle Highlights zu erschaffen, etwa mithilfe von Licht- und Schatteneffekten, Animationen, Partikel-Effekten, Cube- und Normal-Mapping sowie vielen weiteren Funktionen. Darüber hinaus werden mehrere Physik-Engines unterstützt, welche von Drittanbietern veröffentlicht werden und unkompliziert in die Game Engine eingebunden werden können.

Parser und Interpreter

Damit aus einem BlitzBasicScript-Quelltext ein ausführbares Programm wird, bedarf es zweier Komponenten: Parser und Interpreter. Ein Parser analysiert die Struktur des Quellcodes und generiert daraus einen Abstrakten Syntaxbaum (AST), der die Grundlage für die Ausführung von Befehlen und Datenstrukturen zur Laufzeit bildet. Der Abstrakte Syntaxbaum wird als Objekt an einen Interpreter weitergeleitet und Zweig für Zweig abgearbeitet. Jeder Abschnitt der Baumstruktur enthält die nötigen Informationen, um genau die Operationen durchzuführen, welche der Programmierer in seinem Code hinterlegt hat. Sollen etwa die Zahlen 2 und 6 addiert werden und das Ergebnis in eine Variable "sum" geschrieben werden, so besteht der entsprechende Zweig des AST aus folgenden Elementen:

  • Zahl 2 auf der linken Seite
  • Zahl 6 auf der rechten Seite
  • Operation "Addition"
  • Variablenzuweisung des Ergebnisses nach "sum"

Da ein Parser sehr viel Programmierlogik enthält, ist es üblich, einen so genannten Parser-Generator einzusetzen. Dieses Hilfstool erhält als Eingabe eine formale Grammatik der Zielsprache, die aus Regeln besteht, wie die Statements eines Programmes aussehen können. Damit der Tech Stack konsistent bleibt, fiel die Wahl auf den TypeScript-basierten Parser-Generator tsPEG. Dessen wichtigste Eigenschaft ist das Paradigma parsing expression grammar, womit nicht nur kontextfreie, sondern auch kontextsensitive Grammatiken geschrieben werden dürfen. Durch einen unbegrenzten Lookahead wird dies ermöglicht, was jedoch auch dazu führt, dass keine linksrekursiven Grammatiken zulässig sind, da tsPEG sonst in eine Endlosschleife gerät.

Ausblick

Momentan befindet sich das Projekt BlitzBasicScript noch in der Alpha-Phase. Aufgrund der Vielzahl eingesetzter Technologien, sowie der Realisierung als Open-Source-Software ohne definiertes Zeit- und Kosten-Budget, ist es aktuell noch nicht absehbar, wann ein erster Prototyp die Beta-Phase erreichen wird.

Der Umfang der Skriptsprache und die Befehlsimplementierung werden kontinuierlich in agilen Einheiten erweitert. So lassen sich mit der Zeit immer mehr Datenstrukturen und vordefinierte Funktionen nutzen.

Inwieweit es eines Tages möglich sein wird, große Projekte von mehreren tausend Codezeilen Umfang in BlitzBasicScript zu realisieren, kann noch nicht abgeschätzt werden. Es bleibt jedoch zu hoffen, dass durch die ständige Zunahme an Rechenleistung und verfügbarem Speicher in Hardware auch große Programme ohne Performance-Verluste in Echtzeit geparst und interpretiert werden können. Die Entwicklung weiterer Web-Standards durch das W3C wird ebenfalls dazu beitragen, das Spielerlebnis im Webbrowser auf allen modernen Plattformen zu verbessern.