Een van de eerste spellen die ik ooit maakte, was AIRPLANE. Ik programmeerde het als kind in MSX-BASIC. Het was een eenvoudig spelletje waarin je met een vliegtuig door een speelveld vloog en obstakels moest ontwijken. Technisch stelde het natuurlijk niet veel voor, maar voor mij was het destijds pure magie: iets bedenken, regels invoeren en vervolgens een speelbaar computerspel op het scherm zien verschijnen.

Ruim dertig jaar later besloot ik terug te keren naar datzelfde idee en AIRPLANE opnieuw op te bouwen als een echte MSX-cartridgegame in Z80-assembly. Een mooie combinatie van nostalgie, technisch puzzelen en moderne AI-ondersteuning.

Terug naar het oorspronkelijke BASIC-spel

Mijn eerste MSX-games maakte ik tussen 1990 en 1993. Ik was toen tien tot dertien jaar oud en programmeerde tientallen eenvoudige spellen in MSX-BASIC. AIRPLANE was een van die vroege experimenten.

Het oorspronkelijke spel kun je nog altijd direct in de browser starten:

Speel de oorspronkelijke BASIC-versie:
https://webmsx.org/?DISK_FILES=http://www.jeroenderwort.nl/wp-content/uploads/jermsx/AIRPLANE.BAS&BASIC_RUN=AIRPLANE.BAS

De game is eenvoudig, maar bevat al wel de basis van wat mij toen zo aantrok in het maken van spellen: een duidelijk speeldoel, directe besturing en een wereldje dat volledig door code wordt opgebouwd.

MSX-BASIC was daarvoor een fantastische omgeving. Je zette de computer aan en kon meteen beginnen. Commando’s als SCREEN, LOCATE, PRINT, STICK en STRIG gaven direct resultaat. Je hoefde geen ontwikkelomgeving te installeren, geen project aan te maken en niet minutenlang te wachten tot een build klaar was.

Daar stond tegenover dat BASIC relatief langzaam is. Zodra er meer objecten bewegen, botsingen moeten worden berekend of het scherm voortdurend wordt aangepast, loop je al snel tegen de grenzen van de taal aan.

Waarom een remake in assembly?

Zou het mogelijk zijn deze game te upgraden met behulp van AI in Z80 assembly? In assembly krijg je op een relatief langzame 8-bit computer veel meer mogelijkheden.

Maar assembly staat ook wat programmeren betreft vrijwel aan de andere kant van het spectrum ten opzichte van BASIC. Waar één BASIC-opdracht veel werk uit handen neemt, moet je in assembly vrijwel iedere stap zelf uitvoeren. Je werkt rechtstreeks met registers, geheugenadressen, BIOS-routines, videogeheugen en hardwarepoorten. Dat maakt de ontwikkeling ingewikkelder. 

De nieuwe AIRPLANE is een ROM-cartridge die vanaf adres $4000 wordt uitgevoerd. De ROM bevat de gebruikelijke MSX-cartridgeheader en start vervolgens rechtstreeks de initialisatieroutine van het spel. De game bestaat inmiddels uit meer dan drieduizend regels assemblycode en bevat vijftien levels.

Ontwikkelen met Antigravity

Bij het ontwikkelen heb ik gebruikgemaakt van Antigravity als AI-programmeerassistent.

Dat maakte het project extra interessant. Ik had eerder wel wat assembly geprogrammeerd, maar een compleet spel erin bouwen voor de MSX was altijd een brug te ver voor mij. Je moet dan niet alleen alle Z80-instructies begrijpen, maar ook weten hoe de MSX zijn videogeheugen, interrupts, sprites, geluid, slots en cartridges organiseert.

Met Antigravity kon ik in natuurlijke taal beschrijven wat ik wilde maken. Bijvoorbeeld:

  • laat het vliegtuig horizontaal en vertikaal vliegen;
  • controleer botsingen met het landschap;
  • laat watertegels bewegen;
  • voeg varende zeilbootjes toe;
  • maak een titelbeeld in SCREEN 2;
  • speel muziek af via de PSG;
  • zorg dat de ROM ook op een echte MSX werkt.

De AI kon vervolgens code voorstellen, bestaande routines aanpassen en fouten helpen opsporen. Dat betekende overigens niet dat het spel met één druk op de knop werd gegenereerd. Vooral bij retrohardware is het verschil tussen code die logisch lijkt en code die daadwerkelijk werkt behoorlijk groot.

Een emulator vergeeft soms dingen die op echte hardware problemen veroorzaken. Daarnaast kan een kleine fout in een geheugenadres, stackpointer, interrupt-handler of slotselectie ervoor zorgen dat de complete machine vastloopt.

Mijn rol verschoof daardoor deels van iedere instructie zelf schrijven naar ontwerpen, testen, analyseren en gericht bijsturen. Ik moest voortdurend beoordelen of de voorgestelde oplossing logisch was, of zij binnen de beperkingen van de MSX paste en of het resultaat ook echt goed speelde.

AI maakte de ontwikkeling sneller, maar het bleef nadrukkelijk een iteratief proces.

Van een simpel spel naar vijftien levels

De nieuwe versie is veel uitgebreider dan mijn oorspronkelijke BASIC-game.

Je bestuurt nog altijd een vliegtuig, maar de beweging is nu gebaseerd op snelheid en acceleratie. Het vliegtuig springt niet simpelweg van positie naar positie. De horizontale en verticale snelheid worden bijgehouden als 8.8 fixed-point-getallen, waardoor bewegingen vloeiender kunnen worden berekend zonder dat de Z80 floating-pointberekeningen hoeft uit te voeren.

Ieder level bevat een landschap waar je omheen moet vliegen. Onderweg verzamel je munten. Zodra alle munten zijn opgepakt, is het level voltooid.

De game bevat onder andere:

  • vijftien verschillende levels;
  • vijf levens;
  • score en highscore;
  • vloeiende acceleratie en vertraging;
  • botsingsdetectie;
  • geanimeerd water;
  • draaiende munten;
  • bewegende zeilbootjes;
  • explosie-animaties;
  • een titelscherm;
  • levelintro’s;
  • muziek en geluidseffecten via de MSX-PSG;
  • een eindscherm na het voltooien van alle levels.

De hoofdstructuur is een klassieke game loop. Per beeldframe wordt de invoer gelezen, de snelheid aangepast, het vliegtuig verplaatst, de botsingsdetectie uitgevoerd en worden de sprites, animaties, muziek en score bijgewerkt.

Dat klinkt tegenwoordig vanzelfsprekend, maar op een MSX1 moet je daarbij voortdurend rekening houden met de beschikbare rekentijd en het beperkte geheugen.

Tekens, tiles en sprites

Een belangrijke ontwerpkeuze was het gebruik van zowel karaktergraphics als hardware-sprites.

Het speelveld wordt grotendeels opgebouwd uit aangepaste tekens van acht bij acht pixels. Ieder level kan daardoor compact als een raster van tekencodes worden opgeslagen. Dat bespaart veel geheugen en past goed bij de manier waarop veel klassieke MSX-games werden gemaakt.

Het vliegtuig zelf is een hardware-sprite. Hierdoor kan het soepel over het karakterraster bewegen zonder dat voortdurend alle achtergrondtekens opnieuw hoeven te worden getekend. Ook de zeilbootjes worden met sprites weergegeven. 

Een zeilbootje van alleen de letter O

Een grappig detail is dat ik voor een van de grafische elementen eerst een zeilbootje als ASCII-art liet ontwerpen. Het bootje moest binnen een raster van acht bij acht tekens passen en mocht uiteindelijk alleen uit de letter O bestaan.

Zo’n opdracht lijkt misschien nogal willekeurig, maar raakt precies aan de manier waarop je voor een oude computer ontwerpt. Je werkt voortdurend binnen harde grenzen: acht bij acht pixels, een beperkt aantal kleuren, weinig sprites en slechts enkele kilobytes beschikbaar geheugen.

Binnen zulke beperkingen moet je een vorm toch direct herkenbaar zien te maken.

Dat is een belangrijk verschil met moderne gameontwikkeling. Tegenwoordig kun je vrijwel onbeperkt afbeeldingen, animaties en effecten toevoegen. Op de MSX moet ieder bit een duidelijke functie hebben.

SCREEN 1 en SCREEN 2 combineren

Het eigenlijke spel gebruikt een tekenmodus die goed geschikt is voor snel opgebouwde levels. Het titelscherm gebruikt SCREEN 2, waarmee veel gedetailleerdere patronen en kleurinformatie kunnen worden getoond.

Bij het starten van een spel wordt daarom tussen verschillende schermmodi geschakeld. De game initialiseert het beeldscherm opnieuw, uploadt een aangepast lettertype en zet de benodigde patronen, kleuren en sprites in het videogeheugen.

Muziek op drie geluidskanalen

De MSX1 beschikt standaard over een AY-3-8910-compatibele Programmable Sound Generator. Deze PSG heeft drie toonkanalen en kan ruis produceren.

Daarmee moet zowel de muziek als het geluid worden gemaakt.

AIRPLANE bevat routines voor verschillende muziekmodi, noten, volumes, vibrato en drumsimulatie. Ook geluidseffecten, zoals het oppakken van een munt en het neerstorten van het vliegtuig, lopen via dezelfde chip.

De muziek wordt per frame bijgewerkt. Daarvoor gebruikt het spel een interruptgestuurde frameteller. De hoofdloop wacht steeds op het volgende beeldframe en werkt dan ook de muziek bij.

Werken op echte hardware

Een belangrijk doel was dat AIRPLANE niet alleen in een emulator, maar ook op een echte MSX zou draaien: een HX-10 met 16kb geheugen.

Dat leverde een aantal lastige problemen op. Een ROM die probleemloos start in openMSX of WebMSX hoeft namelijk niet automatisch goed te functioneren op ieder fysiek MSX-model.

Een voorbeeld daarvan is het slotsysteem. Het MSX-platform ondersteunt meerdere primaire en secundaire slots waarin ROM en RAM kunnen zijn ondergebracht. Het spel moet daarom correct bepalen waar het geheugen beschikbaar is en de juiste slotconfiguratie inschakelen.

In de initialisatiecode wordt expliciet rekening gehouden met het activeren van page 2 en met subslots, zodat de ROM ook op complexere machines zoals een MSX Turbo R kan werken.

Fijne vlucht 

Met behulp van de MSX Pico heb ik de ROM op een echte MSX gestart. Na de bekende MSX-copyrights kwam het vliegtuig in beeld. Het werkte. Magisch!

AIRPLANE begon als een eenvoudig BASIC-programma van een kind dat wilde ontdekken hoe computerspellen werden gemaakt.

Nu bestaat dezelfde game als een cartridge-ROM, geschreven in Z80-assembly, met vijftien levels, sprites, muziek, animaties en code die rekening houdt met de eigenaardigheden van echte MSX-hardware.

Daarbij gebruikte ik een technologie die destijds pure sciencefiction zou zijn geweest: een AI die mee kan denken over code, bugs analyseert en helpt om ideeën om te zetten in werkende routines.

Leermomenten

Het maken van deze game kostte nog behoorlijk wat moeite. Ik heb heel wat LLM-credits verspeeld met onnodige iteraties. Elke keer als er een update klaar was, brak het op een andere plek weer. 

Een aantal dingen kan ik verbeteren bij het volgende project:

  • Programmeren in C en niet in pure assembly;
  • Gebruik gaan maken van standaard libraries zoals MSXgl;
  • Pak het stapsgewijs aan, zorg dat er goede documentatie is voordat je gaat bouwen;
  • Als iets goed is gedaan, laat de LLM dat dan vastleggen zodat het daarna weer goed gedaan kan worden;
  • Laat de software testen;
  • Maak gebruik van een MCP server om openMSX aan te sturen. 

Ik heb de smaak nu wel te pakken. Als ik weer wat credits heb ga ik maar eens naar de volgende BASIC game kijken die ik kan laten reïncarneren!

Zelf spelen of de broncode bekijken

De nieuwe cartridgeversie kun je rechtstreeks starten in WebMSX:

Speel AIRPLANE:
http://webmsx.org/?ROM=https://www.jeroenderwort.nl/wp-content/uploads/airplane.rom

De volledige broncode staat op GitHub:

Broncode:
https://github.com/Randam/MSX-Airplane

Het project bevat onder andere de hoofdcode, leveldata, grafische bestanden, buildscript en ontwerpregels voor de levels. De repository omschrijft het project toepasselijk als een herleving van mijn allereerste MSX-BASIC-game.

En voor wie wil zien waar het allemaal begon:

Speel het oorspronkelijke AIRPLANE in MSX-BASIC:
https://webmsx.org/?DISK_FILES=http://www.jeroenderwort.nl/wp-content/uploads/jermsx/AIRPLANE.BAS&BASIC_RUN=AIRPLANE.BAS

LAAT EEN REACTIE ACHTER

Vul alstublieft uw commentaar in!
Vul hier uw naam in

Deze site gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie gegevens worden verwerkt.