- Title: Finite State Machines
- Description: In this tutorial, I will teach you how to use Finite State Machines in Game Maker. This makes programming any complex game object lots easier for the programmer.
- GM Version: GM 7/8 (others = script only)
- Registered: script used does not require pro
- File Type: gmk
- File Size: 1 MB
- File Link:
Introduction to teh Finite State Machine (FSM):
What is a "Finite State Machine" you ask?
Well, it's just like it sounds. It is a 'machine' (or system) which allows something to 'exist' in a finite (singular) state.
You're probably wondering what use this is to you. The truth is, absolutely everything! In fact, most, if not ALL, of the games developed professionally by large studios use these. Why? Because they're easy, modular, and very efficient to use for professional game programmers and complete novices alike.
Game Designers come from all walks of life, and even those with programming experience tend not to know the intricacies of the current hardware and/or languages they're using for their project, so low-level design is typically left to the actual game programmers, not the designer. So how do you translate "I want this guy to walk 3 pixels over and jump when he gets close to a wall and stand there in a cool pose if he makes it or look sad when he lands" to a hard-nosed game programmer whose eyes are veiled with the intricacies of hardware programming?
Finite State Machines.
That is, you tell the game programmer exactly what must happen while in each state of an overall (typically arbitrary) action and explain how exactly each of these states must relate to one another. In essence, without one, pseudo-code like this just falls on deaf ears.
In reality, with Game Maker, we are typically both the designer and programmer. However, we still need to make our game from a designer's point of view, whether we know a lot about how to program it or not. And that is the beauty of the FSM. It allows an artist to do a programmer's work with little to no programming experience. However, with Game Maker, we simply put it in as a tiny bit of code in a state that runs as part of a state machine, and it just works! That's because Game Maker is doing the job of the hardware programmer for us and we're giving it pseudo code (more or less) with GML to make it do just what we want.
Now, the difference of using a Finite State Machine versus doing it the old-fashioned way with if statements comes when you realize that you became the "hardware programmer" rather than the game designer at some point. And, when you try to go back to being the "game designer" again, it gets really hard due to the differences in thinking involved. The game designer's method is creative, while the hardware programmer's method is technical and efficient. You end up typing out, line-by-line, a design you wish to create. But, while creativity is great, it is rarely efficient. While the line-by-line method may be creative at first and allow you to see instant results, it is not efficient. That lack of efficiency is exponentially increased with every single line you add, eventually leading to bug-riddled code (due to its complexity) and becoming simply too inefficient to run if you keep at it therefore taking away your ability to even CREATE. You end up trying to be both the "programmer" and "designer" but will ultimately fail at both of them simply because you didn't use the strengths of either one of them. Thus, we have the oh so familiar 'failed game' experience, and I, for one, am really REALLY tired of seeing this! Such amazing projects go to waste because of this! I am here to try my best to prevent it from happening to you!
If you take this article seriously, you will not want to stop programming your games. After all, the focus is on how to make games easily! And, in Game Maker, it isn't hard at all! All you need is a good, working, programming method. And that, my good readers, is what I will teach you right now! So let's get on with the show~!
Let's Talk About States:
Contrary to popular belief, a state is simply "how" an object or entity exists. That is, simply setting a variable state="something" and checking it with an "if" statement is NOT how a state works.
Sadly, games are still programmed this way with Game Maker. They always have and probably always will. Unfortunately this also makes your game VERY VERY complicated when you have many different kinds of states and many kinds of physics that may or may not change depending upon the so called "state" your object is in. This is why people sometimes require many objects to do complex things when these actions could have been done MUCH more easily (and efficiently!) in a single object with a state machine.
Now, as I explained before, a state is "how" an object exists. That is, it usually has a certain sprite and a certain kind of physics applied to it while in that state. However, an object typically won't always exist in that state. That is where the "Finite State Machine" comes in handy. It allows an object to transition into and out of these states. In essence, it allows an object to exist in many different ways, but only one way at a time. A single state can transition to many different states or even just one and then remain in it, for as long as it wants, existing there in whatever way it wants. This allows an organic flow to programming a game object that Game Maker just doesn't natively support for some reason.
An Example of the OTHER method:
I'll program an object now that has a few mutually exclusive fake 'states' as I will call them from now on. Its behavior is to stay in a standing state for 10 steps, display a waiting sprite, then a ready sprite for 5 steps, and then move over 3 pixels while displaying a walking sprite, and then, if he bumps a wall, display a hit sprite and bounce back 3 pixels, otherwise stand in a win pose for 10 steps, and then do it again. To save using alarm events, I will do this all in a step event and assume all the variables used are initialized in the create event (more work btw). "Oh, but that's easy," you say? Well, let us see how easy this is... (and btw, if you're new to GML, feel free to ignore this code; just note it's size and complexity)
if state=="standing" and wait!=10 { wait += 1 sprite_index = spr_standing } if state=="standing" and wait==10 { sprite_index = spr_ready state="ready" wait = 0 } if state=="ready" and wait<5 { wait += 1 } if state="ready" and wait==5 { sprite_index = spr_walk state = "walking" wait = 0 } if state=="walking" and wait< 3 and place_meeting(x,y,wall_object)=false { x += 1 } if state=="walking" and wait< 3 and place_meeting(x,y,wall_object)=true { sprite_index = spr_hit state = "bumped" wait = 0 } if state=="bumped" and wait<3 { x -= 1 wait += 1 } if state=="bumped" and wait==3 { sprite_index = spr_standing state = "standing" wait = 0 } if state=="walking" and wait==3 { sprite_index = spr_win state = "win" wait = 0 } if state=="win" and wait<10 { wait += 1 } if state=="win" and wait==10 { sprite_index = spr_standing state = "standing" wait = 0 }
Phew, what an eyesore. Imagine if that was in addition to the guy's OTHER behaviors such as regular walking or jumping, or being hit by a bad guy? All we wanted to do was make the guy walk over a bit and bounce back if he hit a wall or just stand in a cool win pose if he didn't. I bet you thought "Easy Game Development" was the way of our beloved Game Maker?? Why in the world is something like this so difficult?? Just imagine programming a modern fighting game like that!

Well, I'm here to tell you it's not that Game Maker's too difficult, but you're simply not using it to its fullest capabilities yet. In fact, programming something like that can easily be MUCH LESS time consuming, and thus less prone to errors when using a simple, but infinitely useful, technique known as the "finite state machine".
As a side effect, your code can even become what good game programmers call "modular".
What is this "modular" creature you ask? Well, it's simply stating that, unlike the previous code, everything isn't hard-coded. Your code can be reused in other places. Program the behavior for an enemy through states, for example, and just add sprites, control input, or AI input in an initialization state at your leisure to allow control of that behavior and simply initialize the sprites used on a per-game-object basis, perhaps in their create event.

Making a complex game doesn't have to be hard! You just need to think in terms of modularity. That is, in our case, each state system (or part of state system) should be perceived as a behavior, and, as such, these can easily be reused. But I should probably first teach you how to program these behaviors, right? So let's get on with it!
USING Finite State Machines:
Okay, the fun part! I get to show you something MUCH easier! However, before we can MAKE our behaviors, we must learn how to USE them. However, to use them, you'll need a "State Machine" and for your convenience I've already made a state machine for you. You can find one here in what I call the Zero Engine:
http://gmc.yoyogames...howtopic=454506
This example includes other things that are very useful with a Finite State Machine as well as two more examples of how to use one. The only script we actually 'need' in this engine is the "state_machine" script. It goes in the step event with a script index passed as an argument that is to be our first state. It has the form:
state_machine(st_default);
Now, this script does one thing and one thing only -- it transitions between states. Without this script, it would be impossible to change states or even continue to stay inside one. The argument passed is really just the name of a script without the '()' part. This script, st_default, is where you'll begin programming a default state machine. It doesn't matter the name of it, I just use "st_" to precede my state scripts so I'll be able to know what is (and what isn't) part of a state machine.
First off, before we get into programming our states, you'll need to know a few basic commands and local variables in order to use the state_machine script. These should be defined as constants if you have any trouble using these in conjunction with the variables I show you later in order to prevent any confusion.
We'll start with the commands first:
state_continue
state_repeat
state_next
state_nextnow
These have the form "return(transition_type)" where transition_type is one of the four kinds of transitions between states. These are really all you'll ever need, no matter what you do in a state. The third one is a bit special so we'll come back to it in a bit. However, state_continue simply continues the state we're in currently in the next step (it runs the code for the current script again but lets gamemaker get on doing a few other things it has to do this step first). On the other hand state_repeat will continue repeating this state constantly until it is told to stop, effectively making it the equivalent of a while loop. During that bit of time, nothing else happens outside of running the indicated script so your game may freeze if you don't transition at some point.
Now, state_next and state_nextnow are a bit different than the other two as they require a variable to be set before calling them. This variable, though possibly confusing at first, simply sets the index of the script to be called for the next state and so that is why I named it "next_state".
When transitioning from one state to another, you simply do this:
next_state = st_whatever; return(state_next);
It must be in that order because code execution stops as soon as return() is called, as if it were an exit statement.
Finally, I am going to show you the variables. Unlike the constants we return, these can be changed.
state_time
next_state
state_index
Now, the first one is incredibly handy. It increases by one each step while you remain in a state, but if it so happens that you change a state, it magically resets itself too. However, if you wanted to do stuff at intervals, you could always do something and then reset it to zero every time it reaches a certain value. This won't have any impact whatsoever on the functionality of the state machine as a whole, so abuse it.
Since I've already explained what "next_state" does, I just want to remind you to make a constant to use for the transition values if you tend to be confusing state_next and "next_state". It will make this easier.
Lastly, state_index is a special one. I saved it for last because I want you to forget it exists. Actually, it can be very handy... in the hands of someone who knows what they're doing that isn't all hands (sorry, I need a hand coming up with more hand expressions).
Anyway, tangent aside, this is an alternate way of programming state transitions. You can set the state directly using this variable. Sometimes it is useful if you want to abort a state instantly if a user presses a key for example and you want to use Game Maker's built in events. Otherwise you'd just set "next_state" in that key event and have a script that runs some code and then calls "return(next_state)" each step if you still want to use transitions and gamemaker's input events. However, in the link I gave you earlier, I'm sure it'd be easier to use the universal input scripts I provided while inside a state in order to check for all button presses unless you want to hard-code what buttons a player can use (which isn't a good idea in my personal opinion).
Either way, if you don't understand that last paragraph, feel free to reread it until you do, or forget that final variable even exists and just save yourself some headaches. It's only there for people who want a lot of coding flexibility like myself.
The last thing is arguments. It is always useful to pass arguments between state scripts, however I don't make much use of it personally. Though, if it is necessary, it is definitely there. It has the form:
arg0
arg1
arg2
These are variables that can be set and unset at will. I don't reset them to zero, so you'll have to do that manually after passing them to another script. Just be sure you set them before passing them. Otherwise, they will always be zero or whatever you decided set them to.
The "Finite State Machine" Method:
Finally, we're going to show off what we've learned and do some transitions! PLEASE let it be easier than last time! I don't EVER want to code like that again.
Just a reminder: its behavior is to stay in a standing state for 10 steps, display a waiting sprite, then a ready sprite for 5 steps, and then move over 3 pixels while displaying a walking sprite, and then, if he bumps a wall, display a hit sprite and bounce back 3 pixels, otherwise stand in a win pose for 10 steps, and then do it again.
We'll need only 4 states -- st_standing, st_walking, st_bumped and st_winning. so we'll need 3 scripts. Next, we set our default state in our state_machine() script to st_standing.
In the first script, st_standing, we'll put this code:
if (state_time == 0 and sprite_index!=spr_ready) then sprite_index = spr_standing; //set our stand sprite if (state_time = 10 and sprite_index!=spr_ready) { sprite_index = spr_ready; //set our ready sprite state_time = 0; } if (state_time = 5 and sprite_index==spr_ready) { next_state = st_walking; return(state_next); //leave the state, going to st_walking } return(state_continue); //if nothing happened, stay here
We'll go into the next state (which is for transition demonstration purposes only). This behavior can be shortened, but it can also keep things very organized to use separate states when you need to:
if (state_time = 0) then sprite_index = spr_walking; if (place_meeting(x+1,y,wall_obj)=true) { next_state = st_bumped; //if we bumped something, return(state_nextnow); //we leave this state } if (state_time < 3) then x+=1; //if we're still in this state, we go ahead and move if (state_time = 3) { //however, if we're done moving, we win next_state = st_winning; return(state_next) } //though, f we're still walking, we'll continue trying to walk in the next step return(state_continue);
Now, st_bumped...
x -= 1; if (state_time < 3) then sprite_index = spr_hit //knockback sprite else { next_state = st_standing; //or standing state if we're done being knocked back return(state_next); } return(state_continue) //otherwise we just stay here a few more steps
...and st_winning:
sprite_index = spr_win; //set our sprite for this state if (state_time==10) { //if it's time to be done with our winning pose, next_state = st_standing; return(state_nextnow); //we'll return to the standing state THIS step } return(state_continue); //if we're still posing, let's keep doing that. :)
And we're done! The guy will stand a bit, go into a ready to walk state, walk, and, if he hits a wall, he'll bounce back, otherwise, he'll do a winning pose and then return to standing, doing it all over again.
Closing Comments:
Game Maker is an awesome tool and it seems to be built supporting Finite State Machines, though it never actually says it. I urge you to learn and use this tool well because, whether you think so or not, this way is the most efficient way. After all, you could always program a sprite initialization state and simply export your scripted behaviors, allowing them to be shared with someone else so that they may use them in their games! On top of this, any other game character, enemy or ally, could use the same state machine to set their sprites but behave differently using an input transition system, whether through buttons or through a complicated ai system that emulates those buttons.
As weird and useless as these states are, my example illustrates how quickly and easily a complicated set of actions can be pulled off with a finite state machine without the need of a bunch of if statements. It is very simple to program this way and it makes programming very complicated game characters a breeze.

If you want more examples, check out the Zero Engine which has a couple of state machines programmed in it and what I originally developed this script for in the first place. Hopefully you enjoyed my tutorial. You may even find it in yourself to check out my engine and actually learn how to put these things to use in a game! Whether or not you ever use them for anything serious, they're still really fun to play with!

Edited by Ace, 06 April 2010 - 08:58 AM.