There comes a time when simple state management just will not cut it anymore. I found this out while building up the code base for Thrust’s GUI library. As the objects on the screen became more complex, so did their states. This article covers a new way of thinking about an object’s state, a design that has been proven in Thrust (v1.x). The goals of this state system include the following:
- Easy to use
The system needs to be abstract enough that developers can easily integrate it with their current code. It should be transparent and simple in its most basic form. This means that the idea of an object having a state should require no special implementation code for the developer introducing states to his or her objects.
- Easy to extend
What base layer we build has to be open enough that new states can be defined on the fly or hardcoded. This implies that no constants should be used (Enumerations) and the base layer should understand new states.
- Powerful
This is a very general term, but the point is clear. The state system must be able to have some guaranteed affect on the code we introduce it to. The state system must introduce some way of controlling the objects.
These three guiding rules will help us understand exactly how to design the system. As we understand the implications of each, we need to make some specific assumptions about the platform we are writing for and what each state or object needs to have.
- Support for interfaces, structs and classes
In this case we are using C# and the XNA Framework, but this state system can be applied elsewhere. Thus we need to make the assumption that the platform (and language) we are implementing the system in is Object Oriented and has support for interfaces, structs, classes, inheritance and more.
- Each object will know how to control itself
In Thrust I made the assumption that each object knows how to control itself. This simple means that an object that has a state knows what to do with that state. To understand this better, let’s apply it to humans. A human can be considered to have many states, among them “Asleep” and “Awake”. When a human being is sleeping, it knows to dream, to rest, et cetera. We do not have some outside source telling us to dream. In a similar manor, objects that have state must know what to do in each state.
- Each object has some known functionality
Because we are applying this to XNA, we are going to assume that each object’s known functionality is to be drawn and to be updated. Knowing this functionality will help the state system to understand what to do with each object. You can ignore this assumption in order to implement it in a dynamic manor, but we will save that for a future article.
Now that we understand the goals of the system and what assumptions we need to make, we can start designing the system itself. I will, unfortunately, catch a lot of flak for saying this, but I believe that manager classes do have a place in modern game development. In the situation this article presents, we can utilize a manager class to help objects transition between states. Each object, according to goal number one and two, must be generic in some way. Thus we introduce an interface to define the common functionality.