Dec 30, 2009

Bees in Space, or story of my first freeware game project


It was around five years ago when I decided to try making a small game project on my own and publish it on the internets as freeware.

The reason was that I wanted to experience myself a "full" game development cycle in miniature.

And for fun, of course.

Probably the end result is not such a big deal, but I've certainly enjoyed the process and learned quite a bit from it. Actually doing the things, no matter how small they appear, gives that invaluable insight into their very nature, which can not be gained otherwise. When those small, non-uniform (and often beyond the boundaries of one's present competence) things form a complete whole, a closed loop, then this insight may get even more eyes-opening.

At least that's my feeling about it, in the end.

So now, after five years I've suddenly realized that it was not that bad, after all, and it might be a good idea to reflect on that past thing. Just for fun, again.

Picking a theme
The old-school game called Hexxagon was a primary inspiration for that. It was very tempting, of course, to start something grand, like Diablo or GTAIII clone, but that would obviously defeat the whole purpose of trying to finish the game and see what happens after that.

Being as simple as it is, it still involves quite a bit of work in different areas of programming, gameplay design, user interface, art, "marketing", maintenance and support etc - even though every problem here is a toy one, as comparing to a "real-life" game project.


The Game

Essentially, it's a zero sum, deterministic two-players game, somewhat similar to othello.

In it's simplest form AI for such a game is using minimax algorithm, quite often with alpha-beta pruning optimization, to search the game tree, depth first, to a certain level (or until the time limit is reached).

There is quite a bit of research in this area, with a lot of heuristics proposed to improve the "smartness" of the evaluator and game tree search. They would be certainly interesting to try implementing, but as soon as I've got the basic minimax with alpha-beta pruning working, I decided not to bother with this for the time being.

Again, for the sake of being able to work on other things and finish the game.

The board evaluation procedure was dead simple - it was the difference between the one's and rival's balls, the bigger the better, weighted together with the possibility to move, based on some simple heuristic, details of which I don't remember.

The "board" was represented as a bitmask, wrapped by rows, with bit being set if there is something in the corresponding cell (with "something" having different meaning depending on the context), and the whole board state was represented as a triple of bitmasks: one for black balls, one for white balls, and one for empty cells.

Then the bulk of operations/queries on the board state can be conveniently/efficiently done with the bitwise operations.

This, I believe, is called "bitboards", and is quite common trick when programming similar two-player games.


The Engine
I admit that quite a bit of things here could be done in much simpler way, especially in context of such a simple task at hand.

However, in retrospective it does not look that bad. It was certainly good learning experience, and some of the engine design decisions taken seem to have saved quite a bit of time, which would be otherwise wasted doing boring and repetitive things manually and then fixing all the mistakes done in the process.

Few of the things, in no particular order:
  • Game-specific code was minimal and separated from the rest (an "engine" code)
  • The engine code itself was quite modular and layered, different layers were communicating through the interfaces (for example, widgets are using the sprite manager to display sprites, which is using the renderer interface to draw the textured quads, and the renderer interface can have separate implementations for different graphics APIs - I used to have two of them dx8 and dx9). 
  • Sprites were packed into "packages", using custom format, every sprite was cut into power-of-two chunks in a quadtree, and then those chunks were laid out in runtime on the surfaces in the texture memory cache. There was a custom C# tool which did the packing of the sprites, and generating of the font packages as well.
  • A poor man c++ reflection system (using macro and template tricks) for the classes, derived from the "base game object" class, which made it possible to automatically serialize object hierarchies in text/binary format.
  • Custom text format for representation of the object hierarchies in "scripts". I used XML at first (because I knew that rolling your own is a sin, and XML is the answer), but it turned out to be extremely ugly and hard to edit manually. So I did roll my own (which I called JML), using flex/bison, and it turned out to be not as bad as they said.
  • There is a "data binding" mechanism in scripts, the idea I've borrowed from Qt back then, and then eventually Microsoft has stolen it from me and implemented in WPF :)
  • I've got a set of ad-hoc python scripts which would generate project files (.vcproj/.sln, .dsp/.dsw). Every module had a text file called depends.txt, which used a simple syntax to describe which other internal/external libraries it references. The python script would then walk the source tree, find these files and do the generation. This way I could experiment with different physical source code layouts and manage dependencies explicitly without tinkering for ours in Visual Studio property dialogs.
So, for example, the main menu dialog script would look like this:
dialog "MainMenu"
{
    // ...
    picture "Logo"
    {
        skinpack        = "logo";
        extents         = { 40, 30, 330, 100 };
        stretch         = true;
        skinframe       = 0;
    }

    shortcut "EditorShortcut"
    {
        Key             = "E";
        Action          = >>MenuSystem.OnEditor;
    }
        
    button "ContinueGame"
    {
        text            = L"Continue Game";
        extents         = { 290, 160, 270, 48 };
        font            = "font_menu";
        fontheight      = 48;
        fgcolor         = 0xFF49CD49;
        shadowcolor     = 0xFF11FF11;
        hoverfgcolor    = 0xFF88FF88;
        unpress         = >>MenuSystem.OnContinueGame;
        visible         = <<Core.Game.HasPlayers;
    }
    // ...
}
Design

It was obviously programmer art, from the beginning to end.

I've found a few free sound samples on the internets, painted basic game screen elements myself in gimp (that included the space bee from the main menu screen).

I've used Comic Sans MS in user interface, which is a trademark of amateurish design.The interface itself is not consistent, not intuitive, badly laid out and uses a horrible color palette.

So it's hard to call it a "design", rather an inconsistent pile of placeholders. Which I did realize back then, but again did not overfocus on that, hoping that eventually I might get a help from someone who has a taste and gets interested in this.

The Editor
I've decided to add a certain "non-linear" twist to the original Hexxagon gameplay.

The player would progress through the sequence of "levels", which get more complex in terms of the original board setup (the "smartness" of the computer opponent would still remain the same, as it is essentially the same limited depth/time minimax solution tree search). When certain level is won, it opens one or more new ones, and it's up to player to pick which one to play next.

So, it is not necessary to win all the levels in order to "beat the game". The levels form a kind of a graph with nodes being the particular board setups. And if there is an edge from a source level to destination one, it means that destination is available to play after the source is won.

While all the levels and transitions between them could perfectly be "designed" in Notepad (and probably it would be a better idea to keep it that simple), I've decided to make an "in-game" editor for those.

Which turned out to be pretty rad in the end:



One could pan, zoom the whole graph, select node groups, move them around, double click on nodes and edit them etc.

The whole game, when zoomed away, would look like a big DAG, where the leftmost node here is the starting level, and the rightmost one is the end level, which has to be won to finish the game.

Release
The testing (including the focus testing) was done by myself and my friends. The game was obviously far away from being ready, but at least it was somewhat playable, so I decided not to wait an eternity "til it's done" and publish an early version.

I used NSIS for the installer, and was quite happy with that, as the whole distributable size was below 1Mb, which was pretty good for the downloadable game.

Funny enough, I clearly remember myself not counting the things like making an installer or the game's web page as work, which has to be taken into account.

Turned out, that even with the help of such great tools like NSIS or Inno Setup (which make life much, much easier in this regard), it still took considerable amount of time, especially since I did not have much previous experience in these areas.

So that was another good lesson to learn.

Evaluation
I have submitted "version 0.4" to tucows for evaluation and basically forgot about it, because the evaluation queues are pretty long, and it can take a few months before your software gets there (well, it used to be the case five years ago, but I presume it's not very different today).

So it was quite a surprise for me to finally get my game reviewed and rated... with whooping three cows! Which according to the tucows folks themselves means:
If your application receives a three-, four-, or five-cow rating, congratulations! As you'll see by reading the Ratings Guide, this is no small feat. You are in the company of some of the best programmers in the world. We receive hundreds of requests each week for inclusion in the Tucows software library. The fact that you scored in the three-cow range or higher has earned you a spot on our site. This is a sign that your product is among the best of its kind.
See? My little game is among the best of it's kind!

Seriously, though, I've got an extremely good feedback in an e-mail soon after, where they were giving a detailed explanation about how did they evaluate the game, separately on topics of visuals, sound, fun and longevity, user interface, easiness to grasp etc.

Obviously, graphics, sound and user interface were quite far from being the strongest sides, and that was very expected.

Another weak side was perceived complexity of the game, and most of all that it is very hard for a new person to figure out what are the rules of the game and how to play in general (even though the rules are quite simple).

It was also quite expected, as I was observing it myself during my "focus tests", and was going to "fix" it in later versions by making a tutorial (quite frankly, I had to postpone it to  "later versions" because it also turned out harder than I was originally expecting).  

But still, I've got my three cows and that was quite a revelation.

Aftermath
Well, there is none. Soon after I've decided to change my job and move to live in another country, so it was left where it was, at version 0.4.

I did not finish the game, there were quite a bit of things to do yet, but still managed to experience one iteration of the possible game project life cycle, from beginning to what can be called "end".

It's not on tucows anymore, but still is downloadable on the internets.
I've also made the source code public, and it was available until my hosting period has ended.

But all in all, being a failure it is (i did not really finish the game, and it did not find its players), it still was a success to me personally, in the experience it has brought.

No comments :