On Pre-Processor Macros

For those who have not used C or C++ I’ll start with a brief explanation: There is a thing called the pre-processor, and it is run over source files before they are compiled. It does a bunch of simple and useful things like pulling header files into source files for info about library functions.  Take a look at a tutorial C program, the first line will probably look like this:

#include <stdio.h>

That include line is a preprocessor macro, and it gets information about functions in a library somewhere else. I will be discussing here more complex macros, and their uses and pitfalls.

So I’ve Got a Bunch of Things

Repetition is something which, in programming, should be avoided at all cost. That is, programs will do repetitive tasks all the time, but programmers should avoid doing repetitive tasks like the plague. Most of the time there is a non-repetitive solution which might cost time in the short term, but it’ll save time for the rest of forever. Sometimes it might seem like this is unavoidable: you need a bunch of classes called “Foo”, “Bar”, and “Baz”, but they don’t really do anything important, they just initialise a base class with some data. These classes might look like this:

class Base {
public:
int x, y, z;
};

class Foo : public  Base{
public:
    Foo() : x(0), y(1), z(50) {}
};

class Bar : public  Base {
public:
    Bar() : x(3), y(100), z(3) {}
};

class Baz : public  Base {
public:
    Baz() : x(-6), y(123), z(0xdeadbeef) {}
};

This is repetitive, and a waste of time to write. In the Sim/Management game I’m currently working on, it’s worse still and I’ve got an enum of the names of the base classes too. So rather than waste time writing this out, I set up a pre-processor macro to do it for me.

Pre-processor macros usually look like:

#define SOMETHING Something(); if(Maybe()){ LotsOfStuff();}

but they can also take arguments. And importantly the arguments can be other macros, including other macros which take arguments. In the above list of class definitions there are lots of sections where the only thing that changes is the name (and some numbers, but we’ll get to that). Now that means the code could be replaced by a macro taking that name as an argument. But we can also supply those arguments using a macro if we will be using the same list of arguments frequently!

Here We Go: The Argument List Macro

#define ALLTHETHINGS(f)\
    f(Foo)\
    f(Bar)\
    f(Baz)

To explain, what this does, is given an argument f, it treats f like a function and calls it with Foo, Bar, and Baz as arguments. Note that the preprocessor acts on source code, these are not strings but typeless text, whatever the function of the text is after the macro is processed is what it does – it can be string data, int constants, keywords, or anything else.

An easy example of how this can be used would be to make an enum with these names, this would be most easily achieved by writing the following.

enum Names {
#    define ENAMES(op) op,
    ALLTHETHINGS(ENAMES)
#    undef ENAMES
};

Voila! To add an entry to the enum, just add it to the ALLTHETHINGS macro, and it’ll exist. The reason for undefining the ENAMES macro after its use is we don’t want to leave defined macros lying around where they could cause problems.

That’s no great saving, adding the entry in one place to save adding it in one place, but let’s look again – our definition of the classes above could be made into a macro as well. We will have to make a few changes however, the simplest being not defining the constructor in the class definition, so we only need a macro like:

#define CLASSTYPE(op) \
class op : public Base { \
public: \
     op(); \
};

And we can then use it with the ALLTHETHINGS macro as above. To sort out those constructors we will unfortunately have to repeat ourselves a little. The macro I’ll describe shortly requires the name of the class, as well as the value of the initialisers, it goes like this:

#define CONSTRUCTOR(Type, X, Y, Z)\
Type::##Type() \
    : x(X), y(Y), z(Z) {}

You can then call this as (for example) CONSTRUCTOR(Foo, 0, 1, 50) and it will create that constructor definition for you.

MACROISE ALL THE THINGS

So what’s the downside? If you get it wrong, the error messages are not going to be very helpful. They’ll point to the line which generated the error, but you could have a one line composite macro produce literally thousands of lines after the pre-processor has done its thing. Depending on the mistake you make that could produce thousands of errors as well. The other problem which appears if you work in a nice and friendly IDE, or at least work in Visual Studio, is that code completion is not going to understand what you’ve done. Intellisense will tell you that these classes do not exist and all references to them are errors. Even in Visual Studio Pro 2010, it marks macros inside enums as erroneous.

There is a solution which addresses both of these problems, but I believe has it’s own issues – mainly adding a build step. You could write a small program to expand the macros for you, while not expanding the #include calls. This would mean that the resultant header file would be easy for Intellisense (and non-microsoft equivalents) to parse, and the errors should in theory be easier to trace. Having IDEs call your program as part of the build process is certainly possible, though perhaps not as easy as writing it into a makefile (if you are that kind of developer). It also occurs to me that pre-compiled headers might be a solution, but I’ve never used them so I can’t comment.

I’m no expert on macros, the things I’ve listed above are approaches I’ve used (recently) in my own project. There are many more uses macros may be put to, and many other things the pre-processor can be persuaded to do for you (try looking up template meta-programming, for example) and even many things that they can do to make programming harder. RTFM, and use wisely.

Posted in Programming | Tagged , , , | Leave a comment

SVN

Now and hopefully for the life of the project, there is svn access for those with the capability to build there own copy of the game. Point your favourite svn tool here.

At my end I use Visual Studio 2010 Pro (A leftover from my student years) although I believe there is enough backward compatibility to get it to work with things at least as far back as VC++2008 express. If you wish to not use Visual Studio, then the project requires linking against the following:

  • SDL
  • SDL_main
  • SDL_image
  • OpenGL32
  • glu32

For the truly brave, compiling in linux should be possible, with the openGL libraries renamed appropriately. If anyone does this and finds changes are required, please tell me. If you can give me a patch file, even better!

Posted in Sim Game | Tagged | Leave a comment

On Tile Based Maps

For many types of game, storing your map as an array of tiles can be ideal. Whether you are looking at old school platformers, or more modern 3d games, it can provide at least a basis for a very flexible mapping system. Often in modern games other alternatives are pursued for various reasons, both technical and aesthetic. In the sim game I’m writing, a tile based map is essential to what I want to be able to do. Building and destroying things is going to have a large role in the gameplay, and while this doesn’t necessitate such a map, it can be a very user friendly approach.

Now one of the corner stones of the design is allowing things to be built out of any material, whether that means blocks of stone or swords made of cheese. This means that the two need to be stored independently where possible. Firstly though, we need to examine what these two parts mean in themselves.

Material

Materials will be anything that can, sensibly or not, be used to make things. The first one I added was Air, which will be the most common ‘no material’ material. Others are likely to include Chalk, Granite, Diamond, and yes, Cheese. A material needs to have a visual representation, i.e., a texture, and properties. Properties might include things like weight, hardness, conductivity, transparency, and two-state properties like breathable, passable and so on. Now it’s certain that there won’t be a material matching every possible combination of these properties, which means that storing all of that data for every instance of a material would result in a lot of redundant material.

Instead it’d be better to store a canonical list of materials which exist, and only refer to entries in that list via some suitable enumerator. This principle is something like the Flyweight pattern as mentioned in Design Patterns, an excellently useful, if a little dry, book which I thoroughly recommend.

Blocks

What I referred to earlier as ‘things’ actually needs splitting down a little. Parts of the environment are subtly different from other objects, in that those objects can (or rather, are intended to be able to) be picked up and manipulated by NPCs. Or be NPCs. These will also be considerably less numerous than environment blocks, and so special treatment is something which they can be afforded. Environment blocks then are specifically shapes. Most commonly these will be natural features, or at least what makes them up. Solid blocks, and partial blocks, and such useful shapes. This will inevitably end up including other shapes which are less natural, such as walls, windows and columns.

Map Storage

Now, we need to store, at a minimum, one of each of these things in each. Trying to keep to reasonable computer-friendly numbers, this probably means a byte for each, or 16 bits total, per block. That doesn’t sound like much, but we may want to have a large working set in memory at once, which can add up quickly, and not be very friendly to the CPU cache. A quick search online tells me that a fairly decent processor (the Intel i7) can have an 8MB L3 cache. That’s not that much, not really. That would be filled by a 128x128x256 map chunk. We ideally want to go smaller than that, but the size is something which will require careful balancing with several machines to work out a useful size.

Of course, this 2-byte per tile has its own limitations. As soon as either materials or block shapes number more than 256, that part will require an additional byte. Not too likely, so perhaps not a big worry, but something that might come up a way down the line. The other is that we don’t have any per-tile storage at all. Those blocks must be exactly identical, which means anything that has directions would need to be stored as four separate tiles. This will eat up tile IDs fast, but ensures that the myriad of tiles which don’t need extra data aren’t wasting space. The only other neat way to fix that is to have variable sized tiles, but that destroys any chance at fast indexing.

In Conclusion

Using a Flyweight type design for materials and block types seems to be ideal, although dereferencing the index will add an overhead, it is a necessary one. Fixed sized tiles are necessary, but picking the right size will be key, too little and I’ll have to revisit the whole problem and make any previously generated data out of date, too much and it’ll be too hard to process, take up too much memory, and waste hard disk space. A lot of testing will be required to really decide where to put the boundaries though!

Posted in Programming | Tagged , , | Leave a comment

Sim Game (Working Title)

Sim Game (I’ll pick a better name soon, I promise!) is to be an isometric strategy/management/sim, in the vein of Dwarf Fortress and Dungeon Keeper, with a bit of borrowing from Minecraft. Currently it is being developed in C++ with OpenGL graphics, and a little bit of help from SDL for some of the low-level parts.

This project is very much in the early stages.

Posted in Projects, Sim Game | Leave a comment

New blog

yay wordpress, beats continuing to try to write my own.

Posted in Uncategorized | Leave a comment