Command Interface: Recording input

Hal Brooks
4 min readMar 9, 2022

Objective: Using an interface create a playback system for player commands.

After reset, commands are recorded until done and can be played and rewound.

Set up a new scene with three cubes, and four buttons. Position the buttons and cubes as shown in image above. Tag each cube with the tag, “Cube”. Each button will handle a different feature for playing, rewinding, resetting or indicating the recording is done. Add an empty game object and rename it Command_Manager. The hierarchy should appear as below.

Create a new C# script named ICommand and place it in the Assets > Scripts Interfaces folder. This script uses the interface type and requires two methods be defined in inheriting scripts. ICommand lacks MonoBehavior inheritance and cannot be attached to game objects.

ICommand inteface

The actual commands are set up in separate scripts, for example ClickCommand, shown below. ClickCommand inherits only from ICommand, which must be implemented, and cannot be attached to game objects. This command needs four variables to change the color of an object: GameObject _cube, Color _color, Color _previousColor, and the MeshRenderer _renderer. The ClickCommand() method requires a reference to the GameObject cube and saves a reference to the MeshRenderer in _renderer. The Execute() method, required by ICommand, stores the current color in the _previousColor variable then changes the _renderer.material.color to color. The Undo() method sets the _renderer to the _previousColor.

ClickCommand class inherits from ICommand.

The UserClick script, below, is attached to the Main Camera and checks to see if the player clicks a cube using a Raycast. If the object clicked, hitinfo, is tagged Cube a new click command is created using ClickCommand method or creator using the gameObject hitinfo and a random color. The click then Executes() to change the cubes color and this click is passed to the AddCommand() method within the CommandManager discussed below.

UserClick script on MainCamera.

Select the Command_Manager and add a new C# script named CommandManager. The CommandManager is a singleton, so set up a private static reference to itself, _instance, and a public static reference, Instance, as shown below. The replay system will utilize a list to record commands, _commandBuffer. In void Awake() assign this script to _instance.

CommandMAnager script on Command_Manager game object.

The first method in CommandManager is AddCommand(), which takes the command and adds it to the _commandBuffer list as shown below.

AddCommand() method.

The DoneCommands() method resets the cubes’ colors to white once recording is complete.

DoneCommands() method turns cubes white.

The ResetCommands() method clears the _commandBuffer list then calls the DoneCommands() method to set the cube’s colors back to white.

ResetCommands() method in CommandMAnager

The PlayCommands() starts a coroutine, PlayRoutine(), that Executes() foreach command then waits one second using yield return.

PlayCommands method and PlayRoutine in CommandManager.

The RewindCommands is similar to PlayCommands, except that it plays the list in reverse using the Enumerable.Reverse, requiring the System.Linq namespace, and the Undo() method for the command.

RewindCommands method and RewindRoutine in CommandManager.

Now for each button add an OnClick() event and reference the Command_Manager game object and choose the appropriate method within in the CommandManager script, exemplified for the Play_Button below.

This modular approach to commands, while a little more complicated, uncouples the command from a game object and allows the Command script to be used by any game object. The commands can be easily recorded and replayed.

--

--