Reader small image

You're reading from  Game Development Patterns with Unity 2021 - Second Edition

Product typeBook
Published inJul 2021
Reading LevelBeginner
PublisherPackt
ISBN-139781800200814
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
David Baron
David Baron
author image
David Baron

David Baron is a game developer with over 15 years of experience in the industry. He has worked for some well-known AAA, mobile, and indie game studios in Montreal, Canada. His skill set includes programming, design, and 3D art. As a programmer, he has worked on various games for various platforms, including virtual reality, mobile, and consoles.
Read more about David Baron

Right arrow
Implement a Replay System with the Command Pattern

In this chapter, we will use a classic design pattern named Command to implement a replay system for our racing game. Its mechanism will record the player's controller inputs and the corresponding timestamp. This approach will permit us to play back the recorded inputs in the proper order and with the correct timing.

Replay features are often a must-have in racing games. With the Command pattern, we are going to implement this system in a scalable and modular manner. This pattern proposes a mechanism that permits encapsulating information needed to perform an "action" or trigger a state change. It also decouples the requester of an "action" from the object that will perform it. This encapsulation and decoupling permit us to queue action requests so we can execute them at a later time.

All of this might...

Technical requirements

Understanding the Command pattern

Imagine a platform game in which you can jump over obstacles when you press the space bar. In this scenario, every time you press that input key, you are asking the character on the screen to change states and perform a jump action. In code, we could implement a simple InputHandler, which would listen for a space bar input from the player, and when the player hits it, we would call CharacterController to trigger the jump action. 

The following very simplified pseudo-code sums up what we have in mind:

using UnityEngine;
using System.Collections;

public class InputHandler : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown("space"))
{
CharacterController.Jump();
}
}
}

As we can see, this approach can get the job done, but if we wanted to record, undo, or replay an input from the player at a later time, it could become complicated. However, the Command pattern permits us to decouple the object that invokes...

Benefits and drawbacks of the Command pattern

These are some of the benefits of the Command pattern:

  • Decoupling: The pattern permits the decoupling of the object that invokes the operation from the one that knows how to execute it. This layer of separation allows the addition of an intermediary that will be able to bookkeep and sequence operations.
  • Sequencing: The Command pattern facilitates the process of queuing user inputs, which permits the implementation of undo/redo features, macros, and command queues.

This is a potential drawback of the Command pattern:

  • Complexity: It takes numerous classes to implement this pattern as each command is a class in itself. And it takes a good understanding of the pattern to maintain code built with it. In most cases, this is not an issue, but if you are using the Command pattern without a specific goal in mind, it can become an unnecessary layer of complexity and verbosity in your code base.
Benefits and drawbacks are usually contextual...

When to use the Command pattern

Here's a shortlist of possible uses for the Command pattern:

  • Undo: Implementing an undo/redo system that you find in most text and image editors.
  • Macro: A macro recording system with which players can record a sequence of attack or defensive combos. Then, assign them on an input key to execute them automatically.
  • Automation: Automate processes or behaviors by recording a set of commands that a bot will automatically and sequentially execute.

In conclusion, it's a good pattern for features related to storing, timing, and sequencing user inputs. And if you get very creative with it, you could create some compelling game systems and mechanics.

Design patterns are fun to use if you don't worry too much about staying true to the original academic descriptions. If you don't lose the original intent of the pattern while experimenting with it, you should retain its core benefits.

Designing a replay system

Before describing the replay system design that we will be implementing in this chapter, we have to declare some specifications about our game that can influence the way in which we will implement it. 

Specifications to keep in mind are as follows:

  • Deterministic: Everything in our game is deterministic, which means we don't have any entities with random behaviors, and that makes our replay system simpler to implement because we don't have to worry about recording positions or states of entities that move in our scene like enemy drones. We know they will move and behave the same way during the replay sequence.
  • Physics: We are minimizing the use of the physics features of the Unity engine as our entities' movements are not determined by any physical properties or interactions. Therefore, we do not have to worry about unexpected behaviors when objects collide.
  • Digital: All our inputs are digital, so we do not bother to capture or handle...

Implementing a replay system

This section includes pseudo-code for the sake of simplicity and readability. If you wish to review a complete implementation in the context of an actual game project, open the FPP folder in the GitHub project. The link can be found under the Technical requirements section.

In this section, we are going to build up a simple input replay system prototype using the Command pattern as the foundation.

Implementing the replay system

The implementation will be done in two parts. In the first part, we will code the core components of the Command pattern and then we will integrate the elements that are necessary to test the replay system:

  1. To start, we are implementing a base abstract class named Command, which has a singular method named Execute():
public abstract class Command
{
public abstract void Execute();
}
  1. Now we are going to write three concrete command classes that will derive from the Command base class, and then we will implement the Execute() method. Each of them encapsulates an action to execute.

The first one toggles the turbocharger on BikeController:

namespace Chapter.Command
{
public class ToggleTurbo : Command
{
private BikeController _controller;

public ToggleTurbo(BikeController controller)
{
_controller = controller;
}

public override void Execute()
{
_controller.ToggleTurbo();
...

Testing the replay system

Now that we have the core ingredients of the Command pattern and our replay system in place, it is time to test whether it works:

  1. The first class we will implement is InputHandler. Its primary responsibility is to listen for the player's inputs and invoke the appropriate commands. However, because of its length, we will review it in two parts:
using UnityEngine;

namespace Chapter.Command
{
public class InputHandler : MonoBehaviour
{
private Invoker _invoker;
private bool _isReplaying;
private bool _isRecording;
private BikeController _bikeController;
private Command _buttonA, _buttonD, _buttonW;

void Start()
{
_invoker = gameObject.AddComponent<Invoker>();
_bikeController = FindObjectOfType<BikeController>();

_buttonA = new TurnLeft(_bikeController);
_buttonD = new TurnRight(_bikeController);
_buttonW = new ToggleTurbo(_bikeController...

Reviewing the implementation

We completed the process of building a quick input replay system by using the Command pattern as our foundation. Of course, the code example in this chapter is not production-ready and very limited. Nevertheless, the goal of this chapter was to learn how to use the Command pattern with Unity, and not design an entire replay system.

In the game prototype project in the FPP folder of the GitHub project, we did implement a more advanced example of a replay system that includes serialization and a rewind feature. We recommend checking it out and, of course, modify it at your discretion.

In the next section, we will review some alternatives solutions and approaches that we could have used to build our replay system.

Reviewing alternative solutions

Even if the Command pattern was perfectly suited for our use case, there are some alternative patterns and solutions we could have considered:

  • Memento: The Memento pattern provides the ability to roll back an object to a previous state. This was not our first choice for our replay system because we are focusing on recording inputs and queuing them for replay at a later time, which is very compatible with the design intention of the Command pattern. However, if we implemented a system with a rollback to the previous state feature, the Memento pattern will probably be our first choice.
  • Queue/Stack: Queues and stacks are not patterns, but data structures, but we could simply encode all our inputs and store them in a queue directly in our InputHandler class. It would have been more straightforward and less verbose than using the Command pattern. The choice between implementing a system with or without conventional design patterns is very contextual. If...

Summary

In this chapter, we implemented a simple, but functional, replay system by using the Command pattern. Our goal with this chapter was not to show how to build a robust replay system, but instead showcase how to use the Command pattern to create something in Unity that might be useful for a game project.

I hope you will research alternative ways of implementing the Command pattern that might be better than shown in this book because, like most things in programming, there is no single way of doing things. Nevertheless, at least this chapter offers a first approach to using the Command pattern with Unity.

In the next part of the book, we will start optimizing our code with the Object pool. An essential aspect of a good racing game is consistent performance and frame rate. Everything must run smoothly at every moment, or it might cause our game to feel slow and sluggish.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Game Development Patterns with Unity 2021 - Second Edition
Published in: Jul 2021Publisher: PacktISBN-13: 9781800200814
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
David Baron

David Baron is a game developer with over 15 years of experience in the industry. He has worked for some well-known AAA, mobile, and indie game studios in Montreal, Canada. His skill set includes programming, design, and 3D art. As a programmer, he has worked on various games for various platforms, including virtual reality, mobile, and consoles.
Read more about David Baron