4 Hugues Ross - Blog: Let's make a Roguelike - 1 - Limits
Hugues Ross


Let's make a Roguelike - 1 - Limits


This is a reworked and updated version of a post from about a year ago. Since I've decided to try my hand at this again, and this time in a more organized manner, I felt is would be best to repost this with the necessary edits to catch any newer readers up.

In this new tutorial series, I'm going to be walking you through the process of making a roguelike game from start to finish, with text-based graphics. This tutorial will be written alongside the development of my first non-7drl roguelike project, and all code will be available on Github around the time of posting, with an appropriately-named commit.
This series expects at least basic knowledge of the C programming language, but you can probably follow along in C++ as well, though you may need to adapt some things later on to take advantage of its object-oriented capabilities. If you're new to programming, don't fret--there are plenty of good learning resources online for C, and I'll try to keep my explanations fairly simple.
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.


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. 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 medium. 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 wouldn't recommend it. Instead, the best solution is to use a library.
I'm going to be using ncurses, an implementation of the curses spec. You should be fine with most curses implementations, however. if you're on Windows, or you want your game to be playable outside of a terminal, I would recommend pdcurses. It does a few odd things, but it's common and reliable.


There seems to be an even better version of pdcurses for Windows, available here. I would give it a proper recommendation, but I haven't tried using it myself.

Draw Speed

ncurses, 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 1080p 60fps action game, then you are in for a major letdown. This is probably why most command-line games are either designed to refresh less than once per second, or don't update unless they absolutely must. In fact, if you're making a turn-based game you may be better off forgetting regular draws altogether.
You'll probably want output to be more reactive, only redrawing when things actually change. If you do this, the game will never feel sluggish, and it will use fewer system resources too. This means forgoing most animations, but it also makes things much simpler to work with. Not only that, it may also let you get away with complex calculations, given that you don't have to worry about frame time.


Next, we have a tougher issue. Depending on what sort of terminal or terminal emulator is being run, you're likely to run into a number of color configurations. Most terminals fall under one of these categories regarding color:
  1. Black and White Monochrome terminals aren't as common as they used to be, but they still exist here and there.
  2. 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.
  3. 256 colors I believe this trend started with xterm, but nowadays this is fairly common, albeit less so than the basic 16.
  4. 24-bit color support These are rare, but they definitely exist. 24-bit color (To avoid any confusion, I'm talking about 3 8-bit color channels, rather than 3 24-bit channels) is equivalent to what you can normally draw to a screen (ignoring alpha). It looks like most curses implementations don't currently support this feature, so I won't be covering it.
As you can see, that's an incredibly wide range. Terminals will support fewer colors than their maximum, so most games and applications generally seem to target 2 or 16-color terminals.
Another potential feature is palette swapping. While the default set of colors is fairly predictable, many terminals allow you to change them, giving you more choices to work with if you're careful about managing your colors. However, just like every other feature it isn't guaranteed. 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 demos.
Depending on how many optional graphical features you want to add, the complexity can ramp up significantly. I've decided to try and cover whatever a given terminal throws at me, but I'd recommend that a less experienced coder try to stick to simpler configurations. A good easy setup would be to try 16 color support, and maybe add support for other color setups later down the line.
One upside is that these all have one thing in common: Colors are defined and used in foreground/background pairs, giving you the opportunity to draw 2 different colors per space.


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 isn't necessarily guaranteed. 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 you need to keep them consistent.

Now that we've examined our target platform, we can really start. That will have to wait until the tomorrow's installment, though. For now, let me thank you for reading through all of this. I promise we'll start coding soon!

Next Steps:


Since there will be a short wait between segments, I plan on ending each one with 'homework'. These tasks are designed to build off of whatever I discussed in the tutorial, and if they involve coding I'll usually address them at the start of the next post.
  1. Come up with an idea for a game. If you need inspiration, take a look at Roguetemple for some ideas.

  2. Decide what sort of terminal features you'll be targeting.

  3. Get set up. Make sure you have a decent environment for C programming, and a curses implementation. Ensure that a test program will compile and run properly. While you're at it, make sure that the terminal or platform 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.

  4. Look over an ASCII table, and think about how to best depict the elements of your game. If you plan on using Unicode, browse the charts a bit.

  5. If you don't already know how, learn to use a version control system. I recommend and will be using Git, but plenty of options exist. This isn't required, but it will really help.

No comments: