Sunday, 7 October 2012

Video Game in C: using X macros to define game data

As my brother and I recently released our last video game voxel invaders on android and symbian, I though I would share some of the technical details about it. For my the first post I will talk about a quite useful, although rarely used, C trick known as "X macros", and how we can use it to simplify game code.

The code is written in plain C, and the original design was very simple: all the elements of the game are stored in a structure (called obj_t in the code) that looks like that:

struct obj_t { 
    int type;
    float pos[3];
    float speed[3];
    sprite_t *sprite;
    // A lot of other attributes follow...
};

The important attribute of the structure is the first one: int type. This value allows us to differentiate all the kinds of objects in the game (in C++ I would have probably used subclassing instead). We can see it as a pointer to the object class, except that it is not a real pointer but an index on an array of a structure obj_info_t that contains all the information about a type of object (the game equivalent of a C++ class).

file objects.h:

struct obj_info_t {
   const char *sprite_file;
   float initial_speed[3];
   void (*on_hit)();
   // Lot of other attributes...
};

enum {
   PLAYER,
   ENEMY_A,
   ENEMY_B,
   // And so on...
   OBJ_COUNT
};

file objects.c:

obj_info_t obj_infos[] = {
    // PLAYER
    {
        "data/img1.png",  // sprite_file
        {0, 1, 0},        // initial speed
        NULL             // on hit
    },
    // ENEMY_A
    {
        "data/img2.png",  // sprite_file
        {1, 2, 2},        // initial speed
        enemy_a_on_hit    // on hit
    },
    // And so on..
};

By the way, this kind of design was mostly inspired by the code of the original doom game by John Carmack.

The first improvement we can do is to realize that since we are using C98, we can make the array declaration look better using designated initializers:

file objects.c:

obj_info_t obj_infos[] = {
    [PLAYER] = {
        .sprite_file = "data/img1.png",
        .initial_speed = {0, 1, 0},
    },
    [ENEMY_A] = {
        .sprite_file = "data/img2.png",
        .initial_speed = {1, 2, 2},
        .on_hit = enemy_a_on_hit,
    },
    // And so on.
};

See how the code already looks nice and simple. Although this is how our code looked like for a while, at some point we started to get annoyed by a problem with this pattern. The problem is that every time we define a new enemy, we need to modify too files: the file containing the object types enum, and the file containing the object infos array. Beside, since there is no way to separate the array or the enum into several files, those two files got bigger and bigger. This might not seem too bad, but really it is, specially when you have to find the definition of a given object in the thousand of lines of code containing the obj_infos array.

As I mentioned, the original doom engine also used this kind of pattern, and I think the way they overcame this problem was to use a special tool that would automatically generate the C code for both the enum and the array.

In our case I though writing a C generator tool would be overkill. That is where I realized that there is a simple way to have the C preprocessor generates those two parts (enum and global array) for us. Later when I searched for occurrences of this pattern online I found out this is known as "X macros", there is a very comprehensive article about it from Randy Meyers.

The idea behind C macros is to use a C preprocessor macro that, depending on the context, will expand to either the enum part, either the array initializer part.

In our simple case, it would be something like this:

file object_defs.h:

OBJ(PLAYER,
    .sprite_file = "data/img1.png",
    .initial_speed = {0, 1, -},
)

OBJ(ENEMY_A,
    .sprite_file = "data/img2/png",
    .initial_speed = {1, 2, 2},
    .on_hit = enemy_a_on_hit,
)

file object.h:

#define OBJ(name, ...) name,

enum {
    #include "object_defs.h"
}

file objects.c:

#define OBJ(name, ...) [name] = {__VA_ARGS__},

obj_info_t obj_infos[] = {
    #include "object_defs.h"
}

And so, thanks to this trick, we just need to modify the objects_def.h file to add or remove an object type. Both our enum and our global array will be automatically updated by the preprocessor at compile time. As a bonus, this makes it easy to split the object definitions into several files. For that we just need to #include all the needed files instead of just object_defs.h.

Sunday, 23 September 2012

Voxel Invaders : space invader + 3d voxels



This week we (noctua software) released our new video game for android phone: voxel invaders.
This is the sequel of our previous game Retrocosmos, and it follows the same principle (making a fun space invader game for touch screen devices).  Only this time we used 3d voxels (the equivalent of pixels in 3d) for all the graphics.

Voxels based games are starting to appear more and more and are particularly interesting for independent developers because it is much easier to generate a voxel model than a traditional 3d model.

Anyway back to the game:  this has been written almost entirely in C using android ndk, with just a few java code for some of the stuffs the ndk does not allow to do easily (like controlling the device vibrator). I wrote the engine from scratch, using opengl es 2 for the rendering, and some interesting C hacks using macro for the enemies behaviour state machines (maybe I'll do an other post on that an other time).  The good thing about that is that if the game is a success it will be quite easy to port it to other platforms like iOS or symbian.

From a marketing point of view, we did two versions of the game: a free demo and a full paid version.  We have little experience of this kind of approach so I might do a follow up an other time about how much money we made from that.

Here is a video of the gameplay:



Friday, 23 September 2011

Ascii art Tetris game

I was bored so I wrote this little online tetris game in ascii art.

I hope someone will have fun playing it.

Sunday, 10 July 2011

Voxpaint, an opensource 3d voxels painter

This is the first release of a small 3D voxels painter I had been working on recently.

For the moment it cannot do much, but I am planning to use to create some video game graphics.

The code is hosted on launchpad: https://launchpad.net/voxpaint

Check out the videos:




Tuesday, 28 June 2011

Compiling Qt mobility for Simulator on Windows

These days I am working on a Symbian application using Qt 4.7.3 and Qt mobility 1.2.0.

Since the last version of Qt SDK doesn't ship Qt mobility 1.2.0 for the simulator, I had to recompile it myself. Since it took me some time, I write a step by step how to to help people who are trying to do the same thing.

The only real problem is that the SDK for windows doesn't include all the headers files needed to compile the sources. So I copied them from my linux installation of the SDK.
  1. Make sure you have the latest version of Qt SDK. As I write it it is the version 1.1.2, including Qt 4.7.3 and Qt mobility 1.1.3. In my case the SDK is installed into c:\QtSDK.
  2. Get the sources of qt mobility for the simulator from its git repository. Note that it is not the same repository as for Symbian or desktop version.
  3. Two directories are missing in the the simulator source on windows:
    • c:\QtSDK\Simulator\Qt\mingw\include\private
    • c:\QtSDK\Simulator\Qt\mingw\include\QtGui\private
    So what I did is copied those directory from my linux partition where Qt SDK was installed (from the directory ./QtSDK/Simulator/Qt/gcc/include).
  4. In a windows console, set up the PATH to include all the needed tools. You need qmake from the Simulator SDK, perl, and makew32-make:

    set PATH=c:\QtSDK\Simulator\Qt\mingw\bin;%PATH%
    set PATH=c:\QtSDK\mingw\bin;%PATH%
    set PATH=c:\QtSDK\Symbian\tools\perl\bin\;%PATH%

  5. Run configure. In my case I didn't need the messaging module and since it requires dependencies I removed it from the list of modules using the -modules argument of the command:

    configure -modules "bearer contacts gallery location publishsubscribe multimedia systeminfo serviceframework sensors versit organizer feedback connectivity"

  6. Run the make command:

    mingw32-make

  7. Finally install everything:

    mingw32-make install
After this I was able to compile and run applications using qt mobility 1.2.0 on the simulator.

Monday, 2 May 2011

Gedit plugin to emulate emacs alt-q

Here is a small gedit plugin for all the people who are like me on an emacs rehab.

If there is one emacs feature I really miss when using gedit -which is by the way a great text editor- this is the alt-q command (fill-paragraph), that automatically reformats the current paragraph according to the margin width.

Monday, 21 February 2011

from org-mode to zim

In a previous post I shared my enthusiasm with org-mode, the great emacs module for keeping notes and getting things done.

At the time I was using org-mode for pretty much everything : taking notes, keeping my contacts list, monitoring the time spent working on different projects, etc.

But these days, even though I still think org-mode is one of the most powerful notes taking system out there, I don't use it anymore. Now I am using a mix of hamster and zim. Here is the list of reasons that made me switch from org-mode:


1. I don't use emacs anymore.


I am not going to start the old flame war about emacs vs other text editors, but the fact is that org-mode is only useful for people who know how to use emacs. I don't like to use too many different tools, I am already currently using gedit, netbeans and vim. Having to use emacs at the same time confuses me too much.

2. No integration with gnome


This is specially important for time tracking. I need to be able to see at every moment the task I am working on, and be able to change it in a few seconds. With org-mode I had to switch to the workspace where I run emacs, then enter several commands to see the current task and changing it. Very often when working on a task I would forget to start or stop the timers. In contrast, hamster always show very clearly in the gnome bar what I am doing and the time spent on the task. A simple click and I can stop the task and start a new one.

3. Too complicated (but this is related to the point 1)

Not really a problem for people who use emacs all the time, but when I use it only for org-mode, then I spent many time simply learning the commands. Getting Things Done is all about spending time doing things, not learning about how to do things.

4. Zim organization of files is much better for my needs


The most important thing that org-mode (and zim) got right is that all the data should be stored in plain text files that can be read and edited by any text editor. This way I can always access my notes no matter where. Now the problem with org-mode is that if it works very well with one file per project, it doesn't scale well for wiki style notes where you have many small text files linked to each other. Zim on the other hand make it super easy to have as many files as needed. Each file is automatically added into the ~/Notes directory, which is exactly what I want. On the left

So, here is the typical way I use zim and hamster :

Every morning after I turn on my computer (and I am done reading blogs and emails), I click on the hamster notification to start a new task. The timer always remind me of what I am supped to do, and this is a good physiological fence that prevent me from focusing on anything else that
the current task.

I keep a general Zim note for each project I am working on, that mostly look like a TODO file. Before I start to work I can read it and see what are the important things I should do.

If I suddenly have an idea or find a link that would be useful for a task that is not the one I am working on, I open zim (takes half a second) and add the idea/link in the relevant note.

When I find useful general informations, I add then into my personal wiki that is also managed by zim.

Every time hamster reminds me that I have been working for more that one hour on a task, I allow myself to make a pause, and eventually switch task.

At the end of the day I can review the total time I spent working during the day.

In the end my workflow is pretty much the same as before, but the overall experience is much better than it was with org-mode.

Now of course there are some things I wish I could get from zim / hamster

1. Tables
This is the killer feature of org-mode, and to be honest the only reason I still sometime turn on emacs these days. org-mode just make it super easy to edit tables.

2. Calendar integration
I would love to have gnome automatically parsing my notes for entry containing dates and adding them in the calendar. Once again org-mode had it almost right, except that they don't care about gnome or any other desktop. For them the working environment is emacs.

3. Better wiki syntax and text editing
Disclaimer : I am a fan of restructured text, and I wish that every wiki would use its syntax.
Being a programmer, I feel more comfortable working with mono-spaced font, with if possible a way to automatically format the lines to 80 characters. Currently zim don't allow to edit the notes directly in plain text, and I understand it is the better option for most people, but that is one of the cases where I think more choices would be good.

So should you use org-mode or zim / hamster or something else ?

My opinion: If you already use emacs a lot (and if you like it), then go for org-mode, you can do pretty much anything with it and it can be quite enjoyable to use.

If you don't like emacs, and use gnome, then go for zim/hamster. You can get 80/100 of what you get with org-mode, and you won't spend much time learning it.