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.
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(1);
int height = getArgument(2);
bool fullscreen = getArgument(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:
Future improvementsThat 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 |
