Home

progress towards smaller programs in game development


Over the past few weeks I've worked on creating a framework for developing video games that are smaller, more focused, and more fun to develop. The design I've been exploring consists of having a "video game" actually be made up of two programs: a program that acts as a platform layer by mimicking a graphical terminal and a program that contains the game logic. These two programs (which I'll refer to as the game and the terminal from now on) communicate to each other bidirectionally using a textual application protocol. In this scenario, the game sends drawing commands to the terminal and the terminal will capture events from the window system, gamepads, etc. and communicate them to the game in a platform independent way specific to the protocol. I view this as a more explicit factoring of the platform layer strategy popularized by Handmade Hero.

In Handmade Hero, the platform layer owns the entry point of the game and it does its job by supplying resources in a platform independent way to the game code. For N number of platforms supported, there are meant to be N platform specific entry points that all eventually, in their own specific way, provide the resources needed by the game code. As a benefit, there is only one version of the game code. Likewise, with the system I'm developing, there will be N implementations of the terminal supporting a single implementation of the game logic. Why don't I use the Handmade Hero way of creating a platform layer? I have tried it in the past and I found it to be effective enough. My justification for these feelings is that you don't get the enjoyment of finishing a program when following the Handmade Hero approach, while writing a suite of tools allows you to have small victories along the way. Your mileage may vary! This is a very personal assessment, based off of my gut feelings. Three reasons come to mind for why I feel this way.

First, you can reason about each part separately from the other. The only time you think about the other program is when developing the format for the protocol, such as considering what is easy to parse, what is easiest for the terminal to generate, what information does the game need and when, etc. It is basically foolproof to design the protocol as a non-leaky abstraction.

Second, it is easier to design bottom up, because you can write miniature games or other exploratory programs that use the terminal as independent programs instead of source code that needs to be managed or deleted. While writing the terminal, I created a turtle graphics animation, a tool that echoes the events sent to it by the terminal, a tool that allows me to type commands to the terminal manually as command line arguments, a DVD style screensaver, a program that draws an X corner to corner on the terminal to make sure the protocol design for changes to the width and height of the terminal window is convenient for the game code, and finally an implementation of snake. This is a very fun way to design and program a system, and each of those little programs can be used for testing regressions or remembering how the terminal works. For example, I like to run an instance of the program that echoes the events it reads from the terminal whenever I am writing the event parsing code for another game or small program that relies on the terminal.

Third, since you are programming against a protocol, you don't have to worry about programming a terminal that is cross platform. In some sense, it is nicer to develop two single-platform programs than one multi-platform program. It gives you the freedom to write platform specific code without worrying about trying to wrap it in some way.

There are cons that I noticed, but they don't outweigh the benefits for me. There's a small learning curve for debugging systems of programs that communicate via IPC of some kind. Thankfully, since we can start GDB as a server, we can set up a debugger for both of the programs running simultaneously. I have a feeling GDB is first in class for debugging these kinds of systems.

Another con is that there is a performance cost that needs to be allocated out of the amount of work a game can do per frame. I think it's pretty negligible, since the protocol ends up being high level. The parsing cost and the latency of the IPC mechanism didn't manifest noticeably with the little test programs I have written so far. I would eventually like to program a way to visualize the timeline of what the two programs are doing and when to see just how much latency there is with implementing interprocess communication with pipes. I'm not sure what the most elegant way of doing that is, so I'll put off that work until I am motivated by having a serious game project in production.