Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Let Your Players Undo Their In-Game Mistakes With the Command Pattern

by
Difficulty:IntermediateLength:LongLanguages:

Many turn-based games include an undo button to let players reverse mistakes they make during play. This feature becomes especially relevant for mobile game development where the touch may have clumsy touch recognition. Rather than rely on a system where you ask the user "are you sure you want to do this task?" for every action they take, it is much more efficient to let them make mistakes and have the option of easily reversing their action. In this tutorial, we'll look at how to implement this using the Command Pattern, using the example of a tic-tac-toe game.

Note: Although this tutorial is written using Java, you should be able to use the same techniques and concepts in almost any game development environment. (It's not restricted to tic-tac-toe games, either!)


Final Result Preview

The final result of this tutorial is a tic-tac-toe game that offers unlimited undo and redo operations.

This demo requires Java to run.

Can't load the applet? Watch the gameplay video on YouTube:

You can also run the demo on the command line using TicTacToeMain as the main class to execute from. After extracting the source run the following commands:


Step 1: Create a Basic Implementation of Tic-Tac-Toe

For this tutorial, you are going to consider an implementation of tic-tac-toe. Although the game is extremely trivial, the concepts provided in this tutorial can apply to much more complex games.

The following download (which is different from the final source download) contains the basic code for a tic-tac-toe game model that does not contain an undo or redo feature. It will be your job to follow this tutorial and add these features. Download the base TicTacToeModel.java.

You should take note, in particular, of the following methods:

These methods are the only methods for this game that change the state of the game grid. They will be what you will change.

If you're not a Java developer, you'll probably still be able to understand the code. It's copied here if you just want to refer to it:


Step 2: Understand the Command Pattern

The Command pattern is a design pattern that is commonly used with user interfaces to separate the actions performed by buttons, menus, or other widgets from the user interface code definitions for these objects. This concept of separating action code can be used to track every change that happens to the state of a game, and you can use this information to reverse the changes.

The most basic version of the Command pattern is the following interface:

Any action that is taken by the program that changes the state of the game - such as placing an X in a specific space - will implement the Command interface. When the action is taken, the execute() method is called.

Now, you likely noticed that this interface does not offer the ability to undo actions; all it does is take the game from one state to another. The following improvement will allow implementing actions to offer undo capability.

The goal when implementing a Command will be to have the undo() method reverse every action taken by the execute method. As a consequence, the execute() method will also be able to provide the capability to redo an action.

That's the basic idea. It'll become clearer as we implement specific Commands for this game.


Step 3: Create a Command Manager

To add an undo feature, you will create an CommandManager class. The CommandManager is responsible for tracking, executing, and undoing Command implementations.

(Recall that the Command interface provides the methods to make changes from one state of a program to another and also reverse it.)

To execute a Command, the CommandManager is passed a Command instance, and it will execute the Command and then store the most recently executed Command for later reference.

Adding the undo feature to the CommandManager simply requires telling it to undo the most recent Command that executed.

This code is all that is required to have a functional CommandManager. In order for it to function properly, you will need to create some implementations of the Command interface.


Step 4: Create Implementations of the Command Interface

The goal of the Command pattern for this tutorial is to move any code that changes the state of the tic-tac-toe game into a Command instance. Namely, the code in the methods placeX() and placeO() are what you will be changing.

Inside the TicTacToeModel class, add two new inner classes called PlaceXCommand and PlaceOCommand, respectively, which each implement the Command interface.

The job of a Command implementation is to store a state and have logic to either transition to a new state resulting from the execution of the Command or to transition back to the initial state before the Command was executed. There are two straightforward ways of achieving this task.

  1. Store the entire previous state and next state. Set the game's current state to the next state when execute() is called and set the game's current state to the stored previous state when undo() is called.
  2. Store only the information that changes between states. Change only this stored information when execute() or undo() is called.

The first option is a bit wasteful, but that does not mean it is bad design. The code is straightforward and unless the state information is extremely large the amount of waste won't be something to worry about.

You will see that, in the case of this tutorial, the second option is better, but this approach won’t always be the best for every program. More often than not, however, the second option will be the way to go.

The second option only stores the changes that happen, rather than the entire state. In the case of tic-tac-toe, it is more efficient and not notably more complex to use this option.

The PlaceOCommand inner class is written in a similar way - have a go at writing it yourself!


Step 5: Put Everything Together

In order to make use of your Command implementations, PlaceXCommand and PlaceOCommand, you will need to modify the TicTacToeModel class. The class must make use of a CommandManager and it must use Command instances instead of applying actions directly.

The TicTacToeModel class will work exactly as it did before your changes now, but you can also expose the undo feature. Add an undo() method to the model and also add a check method canUndo for the user interface to use at some point.

You now have a completely functional tic-tac-toe game model that supports undo!


Step 6: Take it Further

With a few small modifications to the CommandManager, you can add support for redo operations as well as an unlimited number of undos and redos.

The concept behind a redo feature is pretty much the same as an undo feature. In addition to storing the last Command executed, you also store the last Command that was undone. You store that Command when an undo is called and clear it when a Command is executed.

Adding in multiple undos and redos is a matter of storing a stack of undoable and redoable actions. When a new action is executed it is added to the undo stack and the redo stack is cleared. When an action is undone, it is added to the redo stack and removed from the undo stack. When an action is redone, it is removed from the redo stack and added to the undo stack.

Undo and redo in game development with the command pattern

The above image shows an example of the stacks in action. The redo stack has two items from commands that have already been undone. When new commands, PlaceX(0,0) and PlaceO(0,1), are executed, the redo stack is cleared and they are added to the undo stack. When a PlaceO(0,1) is undone, it is removed from the top of the undo stack and placed on the redo stack.

Here's how that looks in code:

Now you have a tic-tac-toe game model that can undo actions all the way back to the beginning of the game and redo them again.

If you'd like to see how this all fits together, grab the final source download, which contains the completed code from this tutorial.


Conclusion

You may have noticed that the final CommandManager you wrote will work for any Command implementations. This means that you can code up a CommandManager in your favorite language, create some instances of the Command interface, and have a full system prepared for undo/redo. The undo feature can be a great way to allow users to explore your game and make mistakes without feeling committed to bad decisions.

Thanks for taking interest in this tutorial!

As some further food for thought, consider the following: the Command pattern along with the CommandManager allow you to track every state change during the execution of your game. If you save this information, you can create replays of the execution of the program.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.