Acorn Heroes

Tag: Debugging

Tuning Your Game Made Easy

by on Jul.09, 2010, under Coding, Game Design

Some days it’s hard to think of something to write about, and other days something just falls in your lap. Happily this week it was the latter. It all started with Miguel (as these things often do) – a.k.a. @mysterycoconut on Twitter – posting this article about connecting to an iDevice via telnet while running your App. Using this technique it becomes possible to rapidly tweak parameters on the fly or in fact do all sorts of crazy stuff.

Needless to say I jumped on this idea to aid in tuning my current game prototype. I’ve just reached the stage where rapid tweaking of variables is going to help focus and refine the game play. Miguel suggests hooking a Lua scripting engine into your code, but I thought it would be fun to create my own, plus most of my code is C++ (rather than Objective-C) and I’ve found binding Lua to C++ to be a fiddly process in the past.

The corresponding code for this article can be found here. Note that the DebugServer code comes from Miguel’s article, and the AsyncSocket code comes from here.   I’ve added a minimal amount to Miguel’s code to pass received commands on to the DebugUtils functions found in Debug.[h|mm]. I haven’t had time to create a complete sample project, but the code provided should drop into any existing code base with minimal fuss. If the coding style looks a little strange, you may want to also read this and this.

So, let’s start at the end and work backwards, which I often find to be an effective technique. When tuning a game we spend a lot of time tweaking variables and constants – maximum speed, rate of fire, gravity, item prices, animation durations etc. Wouldn’t it be nice to open up a telnet session to your App and enter a command like “gravity = -8”? Alternatively, maybe there’s a set pattern of enemies that causes a rare bug. Wouldn’t it be nice to enter a “SetupWeirdEnemyPattern” command for easy testing?

So, we have two common scenarios – tweaking a variable and executing a function that alters the game state in a slightly more involved way. The code below allows us to do this. Variables and functions can be “registered” and given a name, which we can then use to adjust values or execute functions via our telnet connection. To make it simple to pass in parameters to these functions, we pass in a set of text parameters using argc and argv, just like the main() function of a C++ program.

Let’s have a look at the public interface to this code:


typedef bool (*DebugCommandFunc)(int argc, char *argv[]);

namespace DebugUtils
{
    void Initialise();

    bool ProcessCommand(const char *command);

    bool RegisterCommand(const char *commandName, DebugCommandFunc commandFunc);

    bool RegisterVariable(const char *variableName, bool *var);
    bool RegisterVariable(const char *variableName, int *var);
    bool RegisterVariable(const char *variableName, float *var);
}

Not much there, is there? The guts of it is in the ProcessCommand() function, where we pass in a string, and magic happens. Or, to provide an example:


bool ResetGameCommand(int argc, char *argv[])
{
// Do stuff here to reset the game state
}

DebugUtils::RegisterCommand(“ResetGame”, ResetGameCommand);

And later, through a telnet connection, we enter “ResetGame”, which in turn calls:


DebugUtils::ProcessCommand(“ResetGame”);

And, just like magic, we reset the game state.

Or as another example, we could register a game variable, say…


DebugUtils::RegisterVariable(“gold”, &gameState.pileOfDubloons);

And then, through the telnet connection, we can tweak this value mid-game, by entering:

“gold = 10000”, or “gold *= 2.0”

I’ve intentionally kept this system as simple as possible, but there’s a lot of power here. It’s very simple to register variables or add short pieces of code that can be run as needed. Just a few examples – turning on debug drawing to see bounding boxes of physics objects, changing the value of gravity or a jump pack’s thrust, loading an arbitrary level, turning off collision detection – the sky’s the limit.

The key thing here is to let you spend as much time as possible refining and tuning your game, because as Jesse Schell describes in his excellent book The Art of Game Design: A book of lenses:

The Rule of the Loop: The more times you test and improve your design, the better your game will be.

In other words, by removing the code-compile-run stage from tuning our game, we can create a better game in less time. Hopefully this code, combined with Miguel’s will provide a simple way to help you refine and debug your game.  Happy tuning!

P.S. I was planning to include a description of how I used TDD (Test Driven Development), but figured this post was long enough. If it’s something you’re interested in though, leave a comment or drop me a note on Twitter (@GeorgeSealy) and I’ll put together an article.

P.P.S. Yes, there’s a few things that could be added to this code to make it even more useful. At the moment it’s not possible to pass a parameter that’s a string with spaces or new lines in it. To do this, you just extend the tokenizing code to respect quoted parameters like “This is a string”.

P.P.S. I’ve resisted the temptation to allow more complex calculations such as “percentComplete = 100 * itemsFound / totalItems”. Most of the time all you want to do is tweak values. If you need this much power, hook in Lua as Miguel suggests, don’t roll your own as it becomes increasingly difficult to maintain as a project matures.

P.P.P.S. I’ve also just realised one of the more useful things I’ve left out – if you just supply the name of a variable on its own, then the variable’s value should be either returned via telnet or printed out using NSLog or similar.  There’s nothing worse than finding the perfect value for something and then being unable to see what it is!

P.P.P.P.S. The observant amongst you may have noticed that the link to Jesse Schell’s book is an Amazon Affiliate link, meaning if you follow that link and subsequently purchase something I may get a small commission. I will only ever put such links to books that I have bought myself or at least read cover to cover and would recommend.

2 Comments :, , more...