3
\$\begingroup\$

I'm trying to get my head around how to create a debug console and have a hard problem to figure out how it access different objects in my game.

Say for example I want the console to be able to:

  • Add new enemies on current map -> This requires access to the current map or some entity service
  • Add a new component to a current entity -> This requires access to some current entity list.
  • Change settings -> This require access to some settings service/manager
  • Change map -> This requires access to some map service/manager
  • Start a new game event -> This requires access to maybe some maps event handle.
  • etc

It seems like this list may just grow and grow with new commands with new dependencies and I wonder how you structre this? How does for example the Half-life console work?

It feels a bit rough to just have something like this:

var console = new DebugConsole() 
console.AddCommand(new AddEntityCommand(entityService)) 
console.AddCommand(new SettingsCommand(settingsService)) 
etc

But maybe that's the way to do it?

\$\endgroup\$
  • 1
    \$\begingroup\$ The code you posted looks great (even as an "ever growing list", it's still quite tractable and understandable). Consider working backwards from what commands you'd like to have, and see what that implies. Some of what comes from that might be similar to what you would need for scripting & testing or even loading/saving game state. \$\endgroup\$ – david van brink Sep 10 '15 at 20:29
1
\$\begingroup\$

That's pretty much the way to do it.

The debug console API should have a method to associate commands the user types in it (such as spawn zombie) with actions. The command pattern, which you've already discovered, is one such method of implementing that association. The debug console exposes an addCommand(string, ICommand) method which associates a string ("spawn") with an instance of a command -- which could just be a delegate or function pointer, it need not actually be some concrete ICommand subclass or whatever. That command is invoked by the console, and the command parses the remaining arguments the user typed ("zombie") to determine what to do.

As for actually hooking up the commands? There's no magic. At some point you're going to have a big list of DebugConsole.AddCommand("spawn", new SpawnCommand(currentMap)) style code. The two basic options are

  • put it all in one place, so it's easy to find it all and extend or modify it.
  • put the bindings for each subsystem (map, spawning, camera, combat, whatever) within that subsystem itself, possibly by requiring the subsystem to implement some attachDebugCommands(DebugConsole console) method that is called during startup or whatever.

There are pros and cons to both. Depending on what information you need each command implementation to have available, it may make more or less sense to take one approach over the other.

Note that in some cases you may need to expose "debug only" APIs out of a subsystem to implement these commands. Languages with preprocessors, like C or C++, can help you ensure that relevant code is only available in debug builds if you like. In other cases, the second of the above two options often lets you expose debug commands that otherwise access private APIs of the subsystem since the subsystem itself is doing the registration.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the great answer. I really like the second idea with attach debug commands. Gonna try to experiment with it later today. \$\endgroup\$ – user1776562 Sep 11 '15 at 7:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.