The first programming language I first seriously studied was QBasic, from a dusty book I found at the back of an ailing computer store in the local mall, not too long before it became a GameStop.
A couple of days ago I found the QBasic interpreter again, because I wanted to remind myself what kinds of things the IDE provided (surprisingly a lot!), and then I started poking around the example programs, which back then I could navigate just enough to fix delay loops or add cheats to Nibbles, but not enough to understand how they worked.
I wondered how hard it would be to port one of the games to HTML5, and then many hours later, Gorilla appears to work. It is not quite pixel-perfect since I wasn’t sure how to reproduce the exact pixels of QBasic’s line, circle, and ellipse drawing commands.
It turns out there are a few bugs in Gorilla because of uninitialized variables. I only fixed one which had to do with level generation — the inverted “V” layout never actually made an inverted “V”.
For sound generation, I had to reimplement QBasic’s PLAY command. Perhaps for realism, but mainly because I’m teaching differential equations right now so have differential equations on my mind, I put in some filter so it wasn’t just a raw square wave. I could have taken an impulse response of a computer case, but instead I made up some quasireasonable values for an LRC filter.
The banana sprites from the game were stored in DATA statements, and it took a while to reverse engineer the format. For some reason, it was basically impossible to find any reference for what was going on in it — the QBasic online help had a formula for calculating the number of required bytes, and the many helpful tutorials on the Internet let me know that I could use GET to produce such data for use with PUT. In EGA mode (SCREEN 9), it stores four “bit planes” one at a time, and then you reconstitute them into a four-bit attribute per pixel, which then is an indexed color you look up in the current palette. May the bananas eternally spin.
I didn’t completely simulate EGA graphics. Instead, for pixel lookups (required by the collision detection!) it just reverses the pixel from the palette to get the pixel’s attribute number.
The whole game is threaded using generators. It’s structured as a coroutine which gives commands to the outer loop, for instance “pause for n milliseconds” or “wait for key press.” This let me keep the program structure basically unchanged from the original QBasic, while letting it be non-blocking, which is necessary to process events, generate audio, and rerender the screen. To give the true Gorilla experience, I put in artificial pauses here and there to make it seem as slow as it would have been in QBasic. One example is during cityscape generation.