Engine Design – Debug Console

I’m currently working on my own game engine and while it’s no where near from being finished, I’ve applied a couple of design patterns when creating the different systems. In the coming weeks I’ll go through a system each at a time and write about how I have implemented them and what problems I might have stumbled upon.


This week’s system is the debug console which I regularly use when debugging or changing stuff on the fly in-engine.

The debug console is one of the first systems which I created in the development of the engine. As such the debug console haven’t been planned out as well or optimized as other systems. But since it’s mostly used during the development process I think that optimization can be focused on other areas of the engine instead.

Now, this is how I have it set up currently.

The way you add a new executable command is trough the addCommand() function. This function takes a struct of the type Command.

The struct looks like this.

struct Command
{
    std::string command;
    std::string help;
    bool open;

    Command(std::string _command, std::string _help = "", bool _open = false)
    {
        open = _open;
        command = _command;
        help = _help;
    }
};

And the way you add a command is like this:

addCommand(Command("window","[width] [height] [fullscreen]", false));

As you can see, there are three arguments tot he constructor but only the first one is mandatory, the rest is optional.

  • The first argument specify what the user needs to write in order to execute the command.
  • The second, argument is a short text which describes what the command does and what parameters it might need to be supplied with.
  • The third and last argument denotes whether the command can be used by the end user who is playing the game. If it’set set to false, then the command wont appear when the user displays the list of all commands.

Now its possible to add commands but its useless unless you cant make use of them somehow.

They way of checking whether the right command is entered is a process involving multiple steps. I’ll demonstrate this through my command for changing window resolution.

if ( getCommand() == "window" )
{
    int width = getArgument<int>(1);
    int height = getArgument<int>(2);
    bool fullscreen = getArgument<bool>(3);
    VideoMode mode(width, height, getVideoMode().bitsPerPixel);

    if ( validateVideoMode(mode,fullscreen) )
    {
        validateCommand("Changed screen resolution");
        setVideoMode(mode, fullscreen);
    }
    else 
    validateCommand("Enter a valid resolution! Changed to default.", WARNING);
} 

There are a couple of extra lines of code to this example but I leave it out for the sake of readability.

First you check that the entered text matches the the command in question. This is done by simply comparing the command in an if statement with the function getCommand(). I have implemented support for multiple arguments to a command with the getArgument() templated function. Where the “T” is what datatype you want to have returned.

In this example I have a way to check that the resolution setting you want to change to is a valid one. If the user inputs an invalid resolution then the validateCommand() function outputs an error in the console. If it’s a valid one then it outputs a normal message and changes the resolution accordingly. The way the output message is formatted depends on the second type argument to the validateCommand() function. The different enum types which a message can be flagged with are:

  • MESSAGE
    The message is a normal text output to the console.
  • WARNING
    The warning is written in yellow text and have a small warning icon next to it.
  • ERROR
    Error messages are special because they are the only ones which don’t store the input in the history of the debug console. They are written in red text and have a small error icon next to them.

Future improvements


That is the basic functionality which my debug console supports at the moment. In later iterations I’d like to have the command execution more streamlined than it is currently. Something like this would be nice to have instead:

A way to register a function so that it is bound to the command could look like this.

addCommand(Command("window","[width] [height] [fullscreen]", false, setVideoMode));

Here the last argument is a function pointer to a function which gets executed whenever the command “window” is called. By doing it this way , I’ll be able to remove all the callbacks which gets scattered throughout the codebase, and instead have a loop which iterates over the commands each frame. But this is only wishful thinking and nothing that I have implemented as of yet.

But that is all I have to share for now. The implementation isn’t pretty but it’s functional and I’ll cover another part of the engine next week.

~Per “Gimmic” Johansson

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s