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
Managing Character States with the State Pattern

In video games, entities continually transition from one state to another depending on player inputs or events. An enemy character might go from an idle state to an attack state depending on whether it spots the player moving across the map. A player character is constantly blending from one animation to another as it responds to the player inputs. In this chapter, we will review a pattern that permits us to define the individual states of an entity and its stateful behaviors.

To start, we will use the traditional State pattern to manage the individual finite states of our main character. In the context of our racing game project, the main character is a motorcycle, so it has a set of mechanical behaviors and animations. As we progress in our implementation of the State pattern, we will soon see its limitations, which we will overcome...

Technical requirements

An overview of the State pattern

We use the State design pattern to implement a system that will permit an object to change its behavior based on its internal state. Thus, a change of context will bring on a change of behavior.

The State pattern has three core participants in its structure:

  • The Context class defines an interface that permits a client to request a change in the internal state of an object. It also holds a pointer to the current state.
  • The IState interface establishes an implementation contract for the concrete state classes.
  • The ConcreteState classes implement the IState interface and expose a public method named handle() that the Context object can call to trigger the state's behavior.

Let's now review a diagram of this pattern definition, but in the context of an actual implementation:

Figure 5.1 – UML diagram of the State pattern

To update an object's state, the client can set the expected state through the Context...

Defining character states

In our game, the entity that will transition between states the most is our racing bike. It's under the player's control; it interacts with almost every element in the environment, including obstacles and enemy drones. Therefore, it will never stay in the same state for long. 

The following diagram showcases a shortlist of finite states for our bike:

Figure 5.2 – Diagram illustrating the finite states of the bike

And now let's define some expected behaviors for some of the listed states:

  • Stop: In this state, the bike is not moving. Its current speed is at zero. Its gears are set to neutral. If we decide that the engine should be on, but running in idle mode in that state, we could have an animation of the chassis of the bike vibrating to show that the motor is running.
  • Start: In this state, the bike moves at full speed, and the wheels turn to match the forward motion.
  • Turn: In the turning state, the bike turns to the left or...

Implementing the State pattern

In this part of the chapter, we will implement the State pattern with the explicit goal of encapsulating the expected behaviors of each of the vehicle's finite states that we defined in the previous section.

We are going to focus on writing minimalist skeleton classes for reasons of brevity and clarity. This approach will permit us to focus on the pattern's structure without being bogged down by implementation details.

It's also important to note that the version of the State pattern presented in this book might be slightly unorthodox as it deviates somewhat from traditional approaches. Therefore, it should be considered a permutation of the State pattern adapted to the context of a Unity project and for a specific use case.

Implementing the State pattern

We are going to review our code example in several steps:

  1. Let's start by writing down the main interface that each of our concrete state classes will implement:
namespace Chapter.State
{
public interface IBikeState
{
void Handle(BikeController controller);
}
}

We should note that we are passing an instance of BikeController in the Handle() method. This approach permits state classes to access public properties of BikeController. This approach might deviate slightly from tradition as usually, it's the Context object that gets passed to the states.

However, nothing stops us from passing both the Context object and the instance of BikeController to the state classes. Alternatively, we could set an instance reference to BikeController when we initialize each state class.

However, it was just simpler to do, as we are going to do for this use case.

  1. Now that we have our interface, let's implement the context class:
namespace...

Testing the State pattern implementation

To quickly test our implementation of the State pattern in your own instance of Unity, you need to follow these steps:

  1. Copy all the scripts we just reviewed inside your Unity project.
  2. Create a new empty scene.
  3. Add a 3D GameObject to the scene, such as a cube, ensuring that it's visible to the main camera.
  4. Attach the BikeController script to the GameObject.
  5. Also attach the following client script to the GameObject:
using UnityEngine;

namespace Chapter.State
{
public class ClientState : MonoBehaviour
{
private BikeController _bikeController;

void Start()
{
_bikeController =
(BikeController)
FindObjectOfType(typeof(BikeController));
}

void OnGUI()
{
if (GUILayout.Button("Start Bike"))
_bikeController.StartBike();

if (GUILayout.Button("Turn Left"))
_bikeController.Turn(Direction...

Benefits and drawbacks of the State pattern

The following are the benefits of using the State pattern: 

  • Encapsulation: The State pattern allows us to implement an entity's stateful behaviors as a collection of components that can be assigned dynamically to an object when it changes states. 
  • Maintenance: We can easily implement new states without having to modify long conditional statements or bloated classes.

However, the State pattern does have its limitations when we use it to manage an animated character.

Here's a shortlist of potential limitations:

  • Blending: In its native form, the State pattern doesn't offer a solution to blend animations. This limitation can become an issue when you want to achieve a smooth visual transition between the animated states of a character.
  • Transitioning: In our implementation of the pattern, we can easily switch between states, but we are not defining the relation between them. Therefore, if we wish to define transitions between...

Reviewing alternative solutions

The following is a list of patterns that are related or alternatives to the State pattern:

  • Blackboard/Behavior Trees: If you are planning to implement complex AI behaviors for NPC characters, I would recommend considering patterns such as the Blackboard or concepts such as Behavior Trees (BT). For example, if you need to implement AI with dynamic decision-making behaviors, then BT is a more appropriate approach because it permits you to implement behavior using a tree of actions.
  • FSM: A question that often arises when discussing the State pattern is the core difference between an FSM and the State pattern. The quick answer is that the State pattern is concerned with encapsulating an object's state-dependent behaviors. However, FSM is more deeply involved with transitioning between finite states based on specific input triggers. And so, FSM is often considered more suited for the implementation of automaton-like systems.
  • Memento...

Summary

In this chapter, we were able to leverage the State pattern to define and implement stateful behaviors of our main character. In our case, the character is a vehicle. After reviewing its structure in the context of a specific code example, we saw its limits when dealing with animated entities. However, Unity offers us a native solution that permits us to manage the states of animated characters with a sophisticated state machine and a visual editor.

However, it doesn't mean that the State pattern in itself is useless in Unity. We could easily use it as a foundation to build stateful systems or mechanics.

In the next chapter, we will define the global states of our racing game and manage them with Event Bus.

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