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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

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:

  1. If the commands are being executed or if the botCommands list is empty, the UndoCommandEntry method won't do anything. Otherwise, it will push the reference to the very last entered command, onto the undoStack. This also removes the command reference from the botCommands list.
  2. RemoveLastTextLine method from UIManager removes the last line of text from the terminal UI so that the UI is consistent with the contents of botCommands when an undo occurs.
  3. RedoCommandEntry does nothing if undoStack is empty. Otherwise, it pops off the last command on top of undoStack and adds it back to the botCommands list via AddToCommands.

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();
    }
  1. Pressing the key U calls the UndoCommandEntry method.
  2. 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:

  1. If you enter a new command, the undoStack should get cleared.
  2. 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!

Phew!

Phew!

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

command pattern victory screen

[/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.

Najmm Shora

Contributors

Najmm Shora

Author

Aleksandra Kizevska

Illustrator

Sean Duffy

Final Pass Editor

Over 300 content creators. Join our team.