About Me
Hello, my name is Alex Schearer. I grew up in New York and currently live in Seattle. I am a software engineer who works on Microsoft Exchange by day and indie games at night, and this is my blog about game development.
More details about me.
Pages
-
Related Posts
Blogroll
Game Design: Decoding State Machines
If you’re a game programmer chances are you’ve worked with state machines. Most likely, you’ve worked with finite state machines informally. For instance, your code might be littered with conditionals such as:
The above code works and certainly gets it’s point across succinctly, but it can get messy quickly. Once the game states become more nuanced, start to involve multiple conditions, and multiply then it’s time to refactor your state machine.
The main advantage accrued is that it’s easier to understand each state and the transitions between states. This makes your code easier to understand for others and yourself down the road. It also makes it easier to find and fix bugs which commonly creep into state machines. The main disadvantage to this approach is that it requires more code to achieve the same thing. That’s why I only recommend it for complex state machines.
Light Approach
Probably the easiest way to formalize your states is to introduce an enum or something similar. I actually recommend that you adopt this approach even for trivial state machines as it makes things considerably clearer with little extra work. Start off by creating an enum for you class, let’s take our example above:
As you can see the above example requires you to rewrite things slightly. Obviously as we are refactoring the result is functionally equivalent. However, the code is much clearer. Now, each conditional clearly encases a single state’s behavior. In addition, transitions are explicit. The result is that new developers will have a much easier time reading and understanding the code. It will also be much easier to find bugs with transitioning from one state to another now that you can clearly follow the state change logic.
Heavy Duty Approach
The last method is great if you’ve got a relatively simple state machine. For example, if you’re working with your game loop which only spans two methods, say
renderandupdate, and a few states. However, if you find your business logic spans multiple methods or you’ve got many states with complex transitions then you may want to adopt an even more formal approach. For instance, in my latest game I have several AI driven critters which move between four or five possible states. Initially I approached the problem using the last approach, but quickly it became very difficult to determine all the different ways to enter or exit a given state. As soon as you find yourself struggling to fully understand all of the possible transitions in your state machine you should consider adopting this approach.To start off you need to identify all the methods where state logic occurs. In my case that was across three methods,
render,update, andonCollision. Once you’ve identified your methods you should define an interface:As you can see I’ve added the three methods relevant for my AI critters. You should replace mine with methods that are relevant to your task. The
entermethod will be called whenever the state is transitioned to. This lets you initialize things as necessary. Theequalsmethod is a simple way for theStateManagerto assist in transitioning between states. You’ll see how this works when I put things together. First, let’s take a look at the state manager.As you can see, the
StateManageris a simple proxy for theStateinterface. While simple, it provides all the necessary logic to help formalize your state machine. The key to this approach is the Java inner class. For each state we will create an inner class implementing theStateinterface. After that we can simply add each state to a state manager and call the manager’s methods when appropriate. This approach makes a state completly explicit by separating its logic into an entirely separate class. Let’s put it all together.There you have it! That was a lot of code so let me try to touch on some of the interesting parts. First off, you’ll notice that I kept the enum. You don’t strictly need this but I think it helps keep things simple and clear. It’s especially useful when implementing the various states’
equalsmethod. Of course, you could just drop the enum and have the states match unique integers. Next notice that each state has its own timer. Now that each state is implemented in its own private class we can separate out all of the various logic and data that they used. I’m sure you can think of at least one instance where you had asleepTimer,awakeTimer, andtimerX, well now you won’t run into that problem! As you can see, by adopting this pattern you alleviate the burden of bookkeeping that you must do. Each state is a self contained unit. This means that it’s much clearer what each state does and how it transitions to another state. It is also much harder to run into a case where one state affects another’s data. Now, this case only comes up when the states are using some of the parent class’s data. (Which sooner or later they will, so you still have to be careful.)Hopefully, you can think of some instances where this pattern would be useful in your project. If you do let me know how it applied and what you found! Also if you have any suggestions on how to improve the approach leave a comment and I’ll update this post.
Related Posts