9/29/14

Let's Make a CLI Game! - 1 - Limits

Just like I said in my last post, this is a tutorial series where we'll follow my attempt to make a strategy game designed to run on the command line. I'm going to be doing this in C, so I recommend that you learn the very basics of the language if you decide to follow along on your own. Lastly, while I'm hoping to teach you something, if you think I've made a mistake or need to be informed of something, then by all means email me or leave a comment below.
WARNING: The following tutorial segment is entirely preparatory. There is no code here, only reading. I think this information is important, but if you don't want to read it then just get through the final section, labelled 'Next Steps.' The next installment will be a bit more exciting.

When you start any coding project, it's especially important to know the limitations of your platform. If you don't, you're liable to cause yourself all kinds of problems later down the line. This can be especially true when you work with something as 'different' as your average terminal. Terminals can be quite limiting environments compared to your average graphical window. Let's examine some of these limits:

The first of limiting factor relates to how things are displayed in a terminal interface. Generally, text is added line-by-line to the window, and there's no apparent way to alter this. It is possible to do so, however. Most(all?) terminals provide a set of special escape sequences that allow you to perform various functions, like moving the cursor, changing text color, and so on. You can actually use these yourself if you know what they are, but I seriously wouldn't recommend it. Instead, the best solution is to just use a library for this. For this, I recommend curses. curses is pretty much the go-to library for building TUIs on most systems. It's extremely common on Mac and Linux systems, and there's a port called pdcurses for Windows. It does a few odd things, but it's common and reliable.

Now, after getting around the first problem we come to another: speed. curses, wonderful as it is, is a bit slow compared to modern hardware-accelerated graphics libraries. It doesn't take long to display things, but if you expect to have a gorgeous 60FPS then you are in for a major letdown. This is probably why most command-line games either have very low framerates, and very little to draw. In fact, if you're making a turn-based game you may be better off forgetting FPS altogether. You'll probably want output to be more reactive, only drawing when things change. This means forgoing most animations, but it also makes things much simpler to work with. Not only that, it may also let you use more complex calculations in your game, which is always a plus.

So far, our issues have been fairly simple. However, the next one is a bit harder. Depending on what sort of terminal or terminal emulator is being run, you're likely to run into color-related issues. Most terminals fall under one of these categories regarding color:

Black and White - Monochrome terminals aren't as common as they used to be, but they certainly still exist.

16 colors - As far as I'm aware, most color-supporting terminals have the same general default 16 colors. They are split into two sets, 8 normal and 8 bright. The colors are black, red, green, yellow, blue, magenta, cyan, and white. Generally, this makes the first 16 colors set for a terminal easy to guess.

256 colors - I believe this trend started with xterm, but nowadays this is fairly common, albeit less so than the basic 16.

Full 24-bit color support - These are rare, but I've heard they exist. 24-bit color is equivalent to what you can normally draw to a screen(ignoring alpha). I've never tried to code for/use one of these before, so I have no real idea how it works.

As you can see, that's an incredibly wide range. Most games and applications generally seem to target the first two, since they aren't too far apart. However, since I'm building a game I'm going to try to support 256-color terminals as well. Another related difference is palette swapping. While the default colors are fairly predictable, many terminals allow you to change them. If that option is available, then much more can be done. However, just like every other feature it isn't guaranteed. Depending on how many optional graphical features you want to add, the complexity can ramp up significantly. Being a coding masochist, I've chosen most of them, but I'd recommend that a less experienced coder try to stick to simpler configurations. A good easy setup would be to try black+white paired with 16 color support, and maybe add 256 color support later if you feel up to it. Palette swapping can get very messy, but can have a great payoff if you have a solid understanding of it. If you don't believe me, look at these.

The final, most obvious limitation is the medium: In the terminal, everything is text! In fact, it's usually just ASCII. Sometimes other fonts and character sets can be supported, but that's no more reliable than color support is. Depending on what is being represented there are a number of methods for displaying things. If you want to draw something large and potentially elaborate, then ASCII art may be the right choice. However, if you want to draw a lot of smaller things, then you may want to only give them one character each, based on what they are. Players are often represented with an @ sign, a dragon could be an uppercase D, and so on. You aren't restricted to using one form of depiction in a game, but it needs to at least make sense.

Now that we've examined our target platform, we can really start. That'll have to wait until the next installment, though. For now, let me thank you for reading through all of this. I promise we'll start coding soon! Next follows a short section that I'll be putting at the end of each tutorial segment, where I provide some tasks for you to try and complete before continuing to the next.

Next Steps:

Come up with an idea for a game, or adapt one that you already had according to the issues addressed above.

Decide what sort of terminal setups you'll be targeting.

Get set up. Make sure you have a decent environment for C programming, and curses. Ensure that curses programs compile and run properly. While you're at it, make sure that the terminal that you use matches your target(s). If you have multiple targets, you need to make sure that you can test for all of them.

Look over an ASCII table, and think about how to best depict the elements of your game.

If you don't already know how, learn to use a version control system. I recommend Git, but plenty of options exist. This isn't required, but if you plan to code any decently large projects then it'll help.