Implementing The Command Pattern In Unity
How to achieve replay functionality, as well as undo and redo in Unity by using the command pattern. Use it to enhance strategy and similar games. By Najmm Shora.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Implementing The Command Pattern In Unity
20 mins
- Getting Started
- Understanding the Bot logic
- Understanding the Command Design Pattern
- Moving the Bot
- Implementing the Command Pattern
- Creating the Commands
- Using the Commands
- Running the Game to Test the Command Pattern
- A Closer Look at the Commands
- Implementing Undo and Redo Functionalities
- Handling Edge Cases
- Where to Go From Here?
- Challenge
Implementing Undo and Redo Functionalities
Run the scene one more time and try to reach the green checkpoint.
You might notice that there is no way for you right now to undo a command that you entered, which means that if you made a mistake you cannot go back unless you execute all the commands. You can fix that by adding an Undo and consequently a Redo functionality.
Go back to SceneManager.cs and add the following variable declaration right after the List declaration for botCommands
:
private Stack<BotCommand> undoStack = new Stack<BotCommand>();
The undoStack
variable is a Stack (from the Collections family) that will store the references to the commands that have been undone.
Now, you will add two methods UndoCommandEntry
and RedoCommandEntry
for the purposes of Undo and Redo respectively. In the SceneManager
class, paste the following code after ExecuteCommandsRoutine
:
private void UndoCommandEntry()
{
//1
if (executeRoutine != null || botCommands.Count == 0)
{
return;
}
undoStack.Push(botCommands[botCommands.Count - 1]);
botCommands.RemoveAt(botCommands.Count - 1);
//2
uiManager.RemoveLastTextLine();
}
private void RedoCommandEntry()
{
//3
if (undoStack.Count == 0)
{
return;
}
var botCommand = undoStack.Pop();
AddToCommands(botCommand);
}
Going through this code:
- If the commands are being executed or if the
botCommands
list is empty, theUndoCommandEntry
method won't do anything. Otherwise, it will push the reference to the very last entered command, onto theundoStack
. This also removes the command reference from thebotCommands
list. -
RemoveLastTextLine
method fromUIManager
removes the last line of text from the terminal UI so that the UI is consistent with the contents ofbotCommands
when an undo occurs. -
RedoCommandEntry
does nothing ifundoStack
is empty. Otherwise, it pops off the last command on top ofundoStack
and adds it back to thebotCommands
list viaAddToCommands
.
Now, you will add keyboard inputs to use these methods. Inside the SceneManager
class, replace the body of the Update
method with the following:
if (Input.GetKeyDown(KeyCode.Return))
{
ExecuteCommands();
}
else if (Input.GetKeyDown(KeyCode.U)) //1
{
UndoCommandEntry();
}
else if (Input.GetKeyDown(KeyCode.R)) //2
{
RedoCommandEntry();
}
else
{
CheckForBotCommands();
}
- Pressing the key U calls the
UndoCommandEntry
method. - Pressing the key R calls the
RedoCommandEntry
method.
Handling Edge Cases
Great — you are almost done! But before finishing, you should make sure of two things:
- If you enter a new command, the
undoStack
should get cleared. - Before executing the commands, the
undoStack
should get cleared.
To do this, first you will add a new method to SceneManager
. Paste the following method after CheckForBotCommands
:
private void AddNewCommand(BotCommand botCommand)
{
undoStack.Clear();
AddToCommands(botCommand);
}
This method clears the undoStack
and then calls the AddToCommands
method.
Now, replace the call to AddToCommands
inside CheckForBotCommands
with the following:
AddNewCommand(botCommand);
Finally, paste the following line after the if
statement inside the ExecuteCommands
method, to clear the undoStack
before execution:
undoStack.Clear();
And you are done! For real this time!
Save your work. Build and click Play in the editor. Type commands as before. Press U to undo the commands. Press R to redo the undoed commands.
Try to reach the green checkpoint.
Where to Go From Here?
You can download the project materials using the Download Materials button at the top or bottom of this tutorial.
To know more about the design patterns involved in game programming, I strongly recommend checking out Game Programming Patterns by Robert Nystrom.
To learn more about advanced C# techniques, check out the course C# Collections, Lambdas, and LINQ on our website.
Challenge
As a challenge, see if you can reach the green checkpoint at the end of the maze. I have provided the solution below in case you are stuck. It is just one of the many solutions you can arrive at.
[spoiler title="Maze Solution"]
- moveUp × 2
- moveRight × 3
- moveUp × 2
- moveLeft
- shoot
- moveLeft × 2
- moveUp × 2
- moveLeft × 2
- moveDown × 5
- moveLeft
- shoot
- moveLeft
- moveUp × 3
- shoot × 2
- moveUp × 5
- moveRight × 3
[/spoiler]
That's it! Thanks for reading. I hope you enjoyed the tutorial, and if you have any questions or comments, please join the forum discussion below!
Special thanks to the artists Lee Barkovich, Jesús Lastra and sunburn for some of the assets used in the project.