Writing a Commodore 64 Game in the 2020s: a Retrospective
A "Cab Hustle" Post-Mortem
Early in 2021, I set out to write a game for a 40-year-old computer, the venerable Commodore 64. The game, Cab Hustle, was finally released in the fall of 2022 after sporadic progress over the months. Early in 2023, I also released a PC version of the game.
In this post, I want to share some insights into how the game came to be, a stroll down memory lane about the motivations, some learnings I made along the way, some thoughts about game development in general, and an update on the proliferation of 8-bit software piracy in the 21st century.
So what’s the game about? In a nutshell, the player steers a small spaceship through the map, landing on platforms to haul passengers for cash. The game is physics-based with the ship being able to thrust and being pulled downwards by gravity. I saw someone online calling it a “Thrust-like,” which is a good way to put it. You can watch the gameplay on YouTube or see the instructions for details.
Motivation & a Stroll Down Memory Lane
Why develop games for the C64 over two decades into the 21st century? I owned a C64 in the 1980s, and ever since I turned it on for the first time, the idea of creating games for it fascinated me. It was also the computer I learned programming on, first in BASIC and then later including some rudimentary assembly.
BASIC on the C64 is slow and limited. There is virtually no support for structured programming, and anything going beyond inputting and outputting characters requires interacting with the hardware directly by writing into memory-mapped registers. There are no BASIC commands for sound or advanced graphics that the machine provides. A common way to create a sprite was to draw the pixels on a piece of quad-ruled paper, translate groups of 8 pixels from binary into decimal values, and then manually enter these values into DATA statements in your BASIC program. To show a sprite on the screen, the program first wrote these values to memory (using POKE commands), then it needed to set a sprite pointer to that data by writing to screen RAM, and finally it set various VIC-II registers to enable the sprite, set its color, and set its coordinates.
I picked up on assembly language using the monitor of the Final Cartridge III, a nifty piece of hardware being stuck into the expansion port that lets you stop the machine and mess with its memory. The built-in assembler does not make things particularly convenient, but it was enough to write simple routines. Better tools existed, but not everything was easy to come by or affordable on an elementary school student’s budget. And at that point, the 16-bit era had begun. With money I had saved and by selling my C64, I was able to make the move onto a new platform: the Amiga.
Fast-forward two more decades, I came across the Dustlayer blog. Dustlayer provides an easy-to-set-up cross-assembler environment alongside tons of documentation on how to get started developing for the C64. Armed with an emulator, I wrote a few small programs, refamiliarizing myself with the system. Several more years passed, and when the pandemic hit, I used the ample at-home time to build a new C64. Now with more time on my hands (and a with physical machine in my hands), I was motivated to finally get a proper C64 game across the finish line.
First of all, what’s the goal for writing the game? I wanted the finished product to feel competitive with software contemporary to the machine. So that puts the bar a fair amount higher than for my pre-pandemic experiments with Dustlayer but certainly lower than top-tier titles like Sam’s Journey. In addition, I was not planning on trying to make this a commercial success, but I was hoping to get it into a state where a handful of people will play it.
As for the topic, I aspired to capture the fun of TurboRaketti on the Amiga, zooming through tunnels at high velocities. TurboRaketti is a two-player split-screen gravity dogfighting game where players fly triangular spaceships through caves and shoot at each other. It takes a bit to master it, and in the beginning most deaths will be the result of crashing into a wall and not from being shot down by the opponent, but once you get a hang of it, it’s immensely fun.
For my C64 game I did not want to start with a two-player game, however. Requiring two players makes testing harder, and it goes against the “handful of people will play it” objective since multiplayer gaming with two joysticks on the same machine is a lot rarer these days than it was back in the 80s. There is the possibility of implementing a computer player, but for my inaugural game I deemed that to add too much complexity.
With those constraints identified, I needed some other driver to get the player to speed through caves. My next thought was utilizing a time-trial racing mechanic, avoiding a second player or computer players that way. However, that did not feel compelling enough as a concept.
Then the passenger-transport mechanic of Space Taxi came to mind. Space Taxi also features a gravity-based flight mechanic, but not with a rotating ship as TurboRaketti does. As a result, the ship is easier to control, but the game is not as fast-paced. To pick up the pace, I’ve adopted a similar scheme as in Crazy Taxi, a more recent 3D arcade game that also has the objective of transporting passengers. In Crazy Taxi, you have to work against the clock by getting time bonuses for dropping off customers quickly. In addition, Crazy Taxi has an element of exploring that resonates with me. The longer one manages to play, the more of the city one gets to see. Therefore, I wanted a larger map than the single-screen rooms that Space Taxi offers, preferably such that players won’t see the whole of it during the first couple of plays so that there’s an incentive to try again.
For the C64 version, I am using cc65, which comes with a C compiler (the namesake of the suite, cc65) and an assembler (ca65). Most of the game’s code is written in C, which makes programming the C64 much more pleasant than using assembly, and experimentation is a lot quicker. For example, dealing with integers larger than 8-bit such as the ones used for the physics is seamless.
The generated C code is mainly unoptimized, but it is fast enough for the game. Some time-critical parts are written in assembly. Most notably, the routine that updates the screen when flying into a new room needs to be fast, so a simple assembly routine handles that. Also, the interrupt service routine (ISR) of the game is written in assembly. The routine runs on specific raster lines on every frame drawn, e.g. to disable sprites just before drawing the status bar at the bottom or to invoke the playroutine for the music, which writes new data to the sound chip every 16-20 milliseconds. Not only does the ISR need to be fast, but it also cannot clobber registers. Cc65 uses various pseudo registers located in memory, and invoking any non-trivial C function will clobber these, so that doing most of the heavy lifting in assembly is easiest.
I’ve created the sprites for the ship and for the explosion using Aseprite. The asset pipeline is implemented in Python and reads sprite PNG images, applies necessary transformations, and outputs the image data as C arrays that can easily be included in the code.
The rooms and character were created with Charpad, a Windows program sold on Itch.io that is specifically designed for this purpose. The exported files are again transformed with Python. For example, symbol names and exports are rewritten so that the ca65 assembler can read them. In addition, the Python code packs the room data using zlib compression. On the C64 side, the data is uncompressed using a decompression routine optimized for the 6502 that conveniently comes with cc65’s libraries.
For the title song, I used GoatTracker. Initially, I gave DefleMask a shot, but I was unable to export a SID file that successfully played on the C64. Furthermore, the exports that DefleMask creates are significantly larger.
Lastly, the final step of building the program is crunching it using pucrunch. That is the equivalent to packing an executable on a modern machine with e.g. UPX. Pucrunch compresses the program at build time and adds a decompressor stub to it. After loading it on the C64, the actual program is uncompressed into memory from the compressed data. Compiling it for PC After finishing the C64 version, I was curious how hard it would be to build a PC version from the same source tree, so I gave it a shot. The PC version leverages most of the C64 C code — some minor modifications were necessary. The assembly parts had to be replaced, but even inefficient, quickly written replacement C code is fast enough on a modern machine.
To compile the code, I am using MinGW-w64 on Linux. The build tools run within Windows Subsystem for Linux (WSL) on my Windows machine. I prefer working with a Linux-based toolchain as opposed to using native Windows tools (i.e. Visual Studio), hence the cross-compiler setup.
The PC version uses SDL2 for graphics, sound, and user input. Graphics and user input are implemented as a shallow emulation of C64 hardware so that the Cab Hustle C code can find what it needs in emulated memory (a 64K byte array).
On the other hand, sound in the PC version is a complete replacement to avoid having to implement an emulation of the sound hardware of the C64. The title music is a recreation of the GoatTracker version using Renoise. The output is compressed using Ogg Vorbis and linked into the binary. The sound effects were created using Supercollider and then also compressed using Ogg Vorbis. The PC version of the game uses SDL Mixer to play those audio files instead of manipulating sound hardware registers like the C64 version.
On a side note, a handful of AV vendors flagged the resulting binary initially. Evidently, an unusual toolchain in combination with a high-entropy data segment (most of it being the Ogg Vorbis-compressed title music) was too much for some engines. (Unusual files can sometimes get caught in the net, see my own commentary in the linked article.)
The first commit of Cab Hustle dates back to April 2021, and I’ve made sporadic infrequent progress on the game up to the initial release October 2022 — mostly working a few hours on a weekend every couple of weeks. As I made progress, I typed up a few blogs but also made a couple of YouTube videos.
My YouTube channel has a small viewership. To my surprise, my videos were nonetheless picked up by other YouTubers vlogging about upcoming C64 games. Olivier from Commodore 64 Mania even helped trying out the game on original C64 hardware — I tried it only in an emulator and on my Ultimate 64. Merci pour ton aide avec le jeu, Olivier!
When Jazzcat reached out on YouTube around last July to see if the game could be ready on time to be added to the Zzap! 64 cover disk for the September/October issue, it was time to, uh, hustle and get the game wrapped up.
The game finally came out as a coverdisk exclusive for the September/October issue of Zzap! 64 magazine. A month later, I released a slightly updated version of the game as a free download on Itch.io as well. After that, I worked on the PC port, which went out on Itch.io after three more months.
The reception of the game was mixed. Leading up to the release, there was some excitement for a modern Space Taxi based on what I could glean from comments in forums or on YouTube. From early feedback, I knew that the game was hard and the controls had a steep learning curve. And when the game was released, that was the main criticism — it’s too hard. Folks that like gravity games quickly got a hang of it, but for many others it was not worth the time investment to master steering the ship.
RetroGamerNation gave it 57% (bumped down from an initial score of 67%). And in the November/December issue of Zzap! 64, the game scored 65%. The reviewers gave it good marks for its presentation but noted the difficulty, both due to the steering and due to the tight time limits.
I saw the game often being described as a Space Taxi clone while the elements added from Crazy Taxi (the tight timer) and TurboRaketti (the physics and controls) were criticized. And that is the crux of the matter — the C64 community wished for a Space Taxi clone, but the game I wanted to make is supposed to capture the fun of flying through caves in TurboRaketti, the ship’s triangular shape being a nod to it.
Other feedback revolved around missing features such as multiple levels, in-game music, better sound effects, different levels of difficulty, etc. My approach was to get a minimal viable product (MVP) out, and with that in mind it was helpful to have the deadline for making the next Zzap! 64 coverdisk, but it also meant that I slashed many ideas that would have added more polish and variety.
Another observation: very few players viewed the instructions, neither the short write-up nor the video version on YouTube. On the one hand, I can tell from the stats of those pages. On the other hand, some player frustrations are actually addressed there (e.g. about obstacles in the next room). That’s something to bear in mind as far as modern expectations of games go: concepts need to be made more self-explanatory or otherwise explained in-game.
Overall, I believe the Zzap! 64 review has it mostly right, and for my first published game at an MVP-level of polish I am content with the results. Moreover, I did not expect all the attention the game got in print, on YouTube, in forums, on Reddit, in podcasts, or on blogs.
Talking about attention: I also did not expect that the C64 cracking scene is still so active. Within hours of a release, there were pirated versions showing up on CSDB. Those versions made additions to the game: instructions, a trainer (unlimited fuel, unlimited time), and of course a cracktro.
Furthermore, the intro music has been ripped and submitted to the High Voltage SID Collection, and you can listen to it online now.
My initial goal was to have a few people play the game, so how did I do? Zzap! 64 has a circulation of a few thousand (but not everyone buying the magazine with coverdisk will play the game). On Itch.io, I’m currently clocking in at a bit over 330 downloads. And then, there are the cracked versions on CSDB, which apparently have been downloaded more than 760 times according to the stats there. Overall, that’s a passable showing for the C64 version.
The PC version, however, is deprived of attention. There were less than 20 downloads on Itch.io. There is a lot more competition for PC games, and a game at MVP stage for the C64 does not even raise an eyebrow for PC gamers.
When I play the game, I tend to play the PC version, which starts up a lot quicker than the C64 version in an emulator and also plays a tad nicer. Primarily, the C64 version has a slight delay when new room data is uncompressed to update the screen. Uncompressing around 250 bytes does not even cause a blip on a modern PC.
There’s a lesson to be learned here as well. If you want to create a game that actually gets attention, is played by people, and generates useful feedback for you, then the C64 is a great platform to start on. There are limitations on what one can do, but working around those is half the fun. And the limitations make it easier to be competitive as a solo developer or a small team.
So what comes next? For starters, a small break from 8-bit programming. For later, I am contemplating incorporating the feedback I got to finally get a game out that the community enjoys and that not just caters to my TurboRaketti nostalgia. That won’t be in the form of improvements of the current game but likely it’d be a “Cab Hustle Deluxe” version or even “Cab Hustle 2.”
A big thank you to everyone who helped out, chimed in, or played the game!
Subscribe via RSS