Gravity Engine interaction and debugging during game development often leads to the creation of a number “backdoor” features in the user-interface of the game to trigger specific tests/experiments during development. These can be seen a number of the demo scenes provided with the GE asset in which sometime significant amounts of UI code (on screen buttons and information panels) are added to demonstate the use of a feature.
GE now provides an alternative approach: an in-scene command line console. This has several benefits:
- Allows interaction with GE to pause, step and dump the state of objects in the scene.
- Permits test and demo functions to be added without extensions to the in-scene UI, reducing visual clutter and oddball key bindings.
- Easily extended with very simple code added only in the new classes (decentralized implementation).
This feature was inspired by the series of game programming videos by Jonathan Blow (Braid/The Witness): Drop Down Console.
Using GEConsole
GEConsole can be added to a scene by dragging the GEConsole object from the prefabs folder into the scene.
The console is normally inactive and is expanded by pressing backquote (`). Pressing this once opens a small console, a second backquote expands the console and a third backquote hides it again.
Once the console is open the list of commands available in the scene can be seen with a ‘?’. These will vary from scene to scene. Commands are added to the scene by those classes that wish to (details below).
For example in the scene PlanetMoonXfer opening the console and entering ‘?’:
This shows help for two classes that have registered commands with GEConsole: GravityEngine and OrbitMGController.
The GravityEngine commands will be present in every scene. They are:
- clear: remove all objects from GE
- dump: show the internal list of objects and their positions and velocities
- fastfwd <time>: fast forward to the specified time (in physics time units)
- go: resume execution
- info <game object name>: provide in-depth information about the named game object, including position and velocity in internal and scaled units.
- pause: pause GE execution
- step: advance GE by one FixedUpdate step
- timezoom <factor>: set the run-time time zoom to the indicated value
Adding Custom GE Console Commands
Adding a custom GE console command requires three steps:
- Create a command in your class that extends GEConsole.GEConsoleCommand
- Invoke GEConsole.RegisterCommandIfConsole() with an instance of the new console command in the Start() or Awake() method of your class.
The definition of GEConsoleCommand is very simple:
public abstract class GEConsoleCommand { //! Full name first (one that will be used when help is displayed) public string[] names; //! Help string (shown when '?' is entered) public string help; //! Name of declaring class (will be filled in automatically) public string declaringClass; //! Function to be run by the console, returning the output to be displayed in the console. public abstract string Run(string[] args); }
When the class being added to is a singleton (like GravityEngine) then the Run() function can make reference to the singleton directly.
In cases where there is not a singleton access for the class, the command will need a reference to class that is adding to it. For example in the OrbitMGController class the code to add a new command is:
GEConsole.RegisterCommandIfConsole(new MoonXfer(this));
and the definition of the command is:
/// <summary> /// Perform a transfer to the Moon with a patched conic xfer /// </summary> public class MoonXfer : GEConsole.GEConsoleCommand { private OrbitMGController omgController; public MoonXfer(OrbitMGController omgController) { names = new string[] { "moonxfer", "m" }; help = "OrbitMGController: moonxfer <patch_conic_angle>\n" + " transfer to the moon with patched conic angle (adds the required maneuver to spaceship)\n"; this.omgController = omgController; } override public string Run(string[] args) { if (args.Length != 2) { return "Require one argument (angle of SOI intersection). 75 is a good default"; } float angle = float.Parse(args[1]); return omgController.MoonTransfer("Moon", angle); } }
Here the command constructor takes are reference to the defining class so it has a reference to use when the command is executed. The implementation of the command is then in MoonTransfer function in OrbitMGController.
See the demo video.