This handy Unity plug-in helps you to implement your own developer console for your game. It's very easy to set up and enables you to call already existing code from the console with little to none effort.
The plug-in also comes with a ui prefab that works out of the box but can be easily extended to your hearts content. There's also a networking prefab to call commands via a TCP client.
If you want to get a quick overview you should check out the demo project. You can also download the package containing only the essential scripts and assets.
If you chose to download the package, you first need to create a canvas. Then drop the Prefabs/Console/Console.prefab
into the canvas and you're done. Start the game and open the console with Tab
, which is the default key.
Try using the default commands like help
or chelp
.
Inside of the ConsoleLogic
script there are already some predefined commands like help
, chelp
, quit
, close
and clear
.
Implementing your own commands is very easy and will be shown in the examples below.
The console searches for objects in the scene with executable scripts. You can mark your script as executable by adding the [ExecutableFromConsole]
attribute just above the class definition.
Aditionally, you have to mark the methods you want to call from the console by adding the [ConsoleMethod]
attribute to them. This attribute takes two arguments: The command name
and a description
(optional). The description will be shown if you call chelp
for the command.
The code below is taken from the demo project. The method RotateCubeBy
is registered as the cube_rotate
command and takes one parameter.
cube_rotation
takes no parameter and just outputs text to the console using an instance of the FormattedWriter
class.
[ExecutableFromConsole]
public class GameControllerCommands : MonoBehaviour
{
public GameObject cube;
private BaseWriter _writer = new FormattedWriter();
[ConsoleMethod("cube_rotate", "Rotates the cube by to the given angle.")]
public void RotateCubeBy(float degrees)
{
cube.transform.Rotate(Vector3.up, degrees, Space.World);
}
[ConsoleMethod("cube_rotation", "Prints the current rotation of the cube.")]
public void GetRotation()
{
_writer.NextLine();
_writer.Write("Current rotation is: ");
_writer.WriteBold(cube.transform.rotation.eulerAngles.ToString());
}
// [...]
}
Similar to methods, parameters can also be documented. This is strictly optional though.
When chelp
is called for a command, the default parameter names are displayed for the usage example.
You can be more specific by adding a [ConsoleParameter]
attribute with defining a custom description for the parameter.
//[...]
public void ScaleCubeBy([ConsoleParameter("Factor. 1 is default")] float factor)
{
//[...]
}
The image below shows a default parameter-name and a custom description using [ConsoleParameter]
.
If you run into any problems, you may find some answers here.
If you want the commands of any script to appear in the console, there should always be an instance of it in the scene. Scripts without instances will not show up in the console.
- GameObjects containing executable scripts should be limited to one instance per scene to avoid ambiguity.
- Commands should have distinct names across all executable scripts.
- Only use one
BaseConsoleIO
instance per scene. You cannot use bothNetworkIO
andConsoleIO
concurrently.
These things might be helpful for you while working with the console.
As long as the string, you want to pass, doesn't contain any spaces, you don't need to add quotes. When there are spaces, however, your string parameter has to start and end with double quotes so it can be interpreted as a single parameter.
If the string should also contain double quotes the escape sequence \"
can be used.
GameObjects
in the scene can also be passed to methods as parameters.
If you pass a GameObjects
name to the command, the reference to the GameObject
will automatically be resolved and passed to the function.
[ConsoleMethod("destroy", "Destroys the object with the given name.")]
public void DestroyObject([ConsoleParameter("Name of object.")] GameObject gameObject)
{
Destroy(gameObject);
}
The command above could be used like
> destroy someObject
or
> destroy "some object"
for names containing spaces.
For Vector3
or Vector2
types, just pass the different axis values separated by commas without spaces.
Input | Result |
---|---|
some_command 1,2,3 | new Vector3(1f, 2f, 3f) |
some_command 1,2 | new Vector3(1f, 2, 0f) |
some_command 1 | new Vector3(1f, 1f, 1f) |
Input | Result |
---|---|
some_command 1,2 | new Vector2(1f, 2f) |
some_command 1 | new Vector2(1f, 1f) |
Colors can also be passed as parameters. Currently r, g, b, a
, r, g, b
, Hex values
and color names
are supported.
Input | Result |
---|---|
some_command 255,0,0,255 | new Color(1f, 0f, 0f, 1f) |
some_command 255,0,0 | new Color(1f, 0f, 0f) |
some_command #00FF00 | new Color(0f, 1f, 0f) |
some_command blue | new Color(0f, 0f, 1f) |
See the unity documentation for a comprehensive list of the supported colors. The input is case insensitive, so bLuE
is a valid color.
In order to write your own conversions, you have to create a new class inheriting from BaseConverter<T>
, where the generic parameter T
is the type you want to convert to.
Every conversion method has to be tagged with the [ConversionMethod]
attribute. The methods names are irrelevant, only the parameters are important. When the user enters two parameters, like 1,2
, the BaseConverter will search for any method with two parameters and tries to convert the types accordingly. If no errors occur up to this point, the conversion method will be invoked.
This all happens automatically, so you don't have to register your new class anywhere and there is really no other logic to implement than the actual conversion. A complete implementation could look like the following example:
public class Vector2Converter : BaseConverter<Vector2>
{
[ConversionMethod]
public Vector2 Convert(float x, float y)
{
return new Vector2(x, y);
}
[ConversionMethod]
public Vector2 Convert(float x)
{
return Vector2.one * x;
}
}
Try to avoid ambiguities.
- There should always be only one conversion class per type.
- Conversion methods are identified by their parameter count. Don't implement several methods with the same amount of parameters, even if the types are different.
All commands entered by the user are stored. Use the arrow keys to navigate through earlier inputs. The amout of commands stored is limited to 10 by default.
The ConsoleLogic
script reads and writes to the UI via the ConsoleIO
script. ConsoleIO
inherits from the BaseConsoleIO
abstract class and can therefore be replaced with any other class inheriting from this base class.
As an example, I've also implemented a NetworkIO
class that starts a TCP server to receive commands remotely. The client will send the input to the server, is executed and the output will then be sent back to the client. A client implementation can be downloded here.
A custom BaseConsoleIO
implementation usually requires you to also implement a custom BaseWriter
class to format the output correctly.