Jump to content


Photo
* * * * - 7 votes

Finite State Machines


  • Please log in to reply
90 replies to this topic

#1 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 15 January 2010 - 06:10 PM

  • 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:
    Posted Image




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.

  • 8
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#2 Millennial Phungus

Millennial Phungus

    GMC Member

  • GMC Member
  • 278 posts
  • Version:Unknown

Posted 18 January 2010 - 05:05 AM

Hmm... very interesting concept. The example is really well documented and I was able to follow it through pretty easily.

How specific or general should states be in a FSM? If a character has a 1-2-3 combo, should each part be a separate state or is it better to just make a st_attack state and use a variable to keep track of what part of the combo they are on?

Also, I wasn't sure how you would do a state change from a different object (through a with statement or something along those lines). Is this an occasion when changing state_index is necessary?

This was a really helpful guide and has convinced me to try and implement a FSM into my project.
  • 0

Insert witty signature here.


#3 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 18 January 2010 - 06:38 AM

How specific or general should states be in a FSM? If a character has a 1-2-3 combo, should each part be a separate state or is it better to just make a st_attack state and use a variable to keep track of what part of the combo they are on?

Also, I wasn't sure how you would do a state change from a different object (through a with statement or something along those lines). Is this an occasion when changing state_index is necessary?


Thanks for your comments! I'm really glad it was helpful to someone! I nearly lost hope with so many views and no responses.

Either way, to answer your question, most game programmers use a quick state change for each attack in the combo. Action games like that tend to have movement during the animations. So if one of these attacks happen to send the player upward for, say, an uppercut, you could move the character upward during that state until the animation ends. However, if you were to do it like you said with a variable, it wouldn't allow you this freedom to change the physics without getting into that hard-coded stuff again. Chances are, even if your character is staying on the ground, you'll still want to make him move forward a few pixels during the attack animation, at least during the first few steps of it, and the second attack is probably stronger or more direct so you'll probably want to move him forward even faster or farther during that attack animation, and so on. If movement is desired whatsoever, I would require separate states for this. Even if it's not always practical, it at least keeps things from getting jumbled up and complicated and keeps your code easy to read (and therefore edit).

So, to put it simply, don't be afraid to use more states. Unless what you're doing is purely for the sake of animation (such as the standing/jumping/falling and shooting sprites in my MegaManX example) then there is a pretty big chance you could use a new state at some point in conjunction with the one you're currently programming. After all, if there is any potential of physics involved (such as the Megaman object's dash) or complex sprite changing to do with button holding/timing stuff, you will probably always want a new state for this. However, passive stuff like a shooting animation during a standing/running state would be more efficient to leave in the standing/running state rather than making a new one. After all, the difference between standing and running is simply a sprite and a bit of horizontal movement. Why use a separate state? Unless your running involves complicated physics (such as bouncing for example), it's best to simply change the sprite.

And to answer your second question, if you're doing normal transitions in a local object using the typical mechanism (i.e. letting the states change themselves) and you need to switch to a hit state for example because an object just hit you, you might want to check the "state_index" first before changing it (because you might be doing a dodge for example and be invincible at the moment). If you're sure it really is okay to change it, "object.state_index = st_smth;" is very okay to use in that situation. It will have to happen next step though (unless the state itself is checking for the collision and you return state_nextnow to go there instantly). Since state_index is only executed once per step by default, it's probably overkill to use the with() statement since you're only setting a variable in that object, not actually executing the state (until the next step of course).

Also just fyi, I'd advise not using GM's built in button events to change states if you have complex and intertwined states and are using the regular transitions. Use the input system in that example instead. It's made for states, plus it's got a universal input mechanism as well as automatic joystick support. You don't have to, but it makes checking buttons during states a LOT easier since GM doesn't tell you how long each individual key has been pressed like my scripts do.

Edited by Ace, 18 January 2010 - 03:10 PM.

  • 1
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#4 kickassgames

kickassgames

    GMC Member

  • GMC Member
  • 230 posts

Posted 18 January 2010 - 07:01 AM

Hmm, this is very interesting, and it makes things seem way easier. If someone doesn't understand, basically you are writing the code, but this makes it so you don't have to write the same code over and over, so basically this could reduce file size as well, IMO it sounds like Dll's. that is if i am understanding this properly myself :D
  • 0
Come fight me fool:
Click HERE

#5 teej

teej

    The PIXEL'er

  • GMC Member
  • 841 posts
  • Version:GM:Studio

Posted 20 January 2010 - 03:52 AM

Serious developers should take a note of this tutorial, his implementation of FSM is great and is there for you to utilize. It's not only for keeping all state actions in an organized manner (which makes it not hard to come back after months of inactive programming) but it makes things easier coding-wise since it is functional, not only to one object. It is better if you start your projects with FSM modules he provided, if your platformer is going nowhere, get all your resources and use his ZeroEngine, which to me has lots to offer; for flexibility, ease of use, and features.
  • 1

#6 GStick

GStick

    All Secrets Exposed

  • GMC Member
  • 1961 posts
  • Version:GM:Studio

Posted 22 January 2010 - 09:25 PM

Showdown Academy uses states, of some sort anyway. I've never really learned about them myself, I've just been programming the game in a way, which, overtime, seems to look similar to this.

Pretty useful having things stored in separate scripts.
  • 0

Posted Image
The next generation of Game Maker fighting games? More like the best.
Showdown Academy | Showdown Academy Blog


Check out my new album at last.fm: KatazTrophee

#7 safwat1995

safwat1995

    GMC Member

  • New Member
  • 394 posts
  • Version:Unknown

Posted 25 January 2010 - 10:51 AM

Incredible! makes life easy :medieval:
by the way, what's return(st_continue); in the win script? it should be state_continue, right?
  • 0

#8 queviltai

queviltai

    Cat

  • GMC Member
  • 445 posts

Posted 25 January 2010 - 11:52 AM

Wow! I can't believe nobody thought of this before.
  • 0

#9 Nocturne

Nocturne

    Nocturne Games

  • Administrators
  • 25708 posts
  • Version:GM:Studio

Posted 25 January 2010 - 02:14 PM

Wow! I can't believe nobody thought of this before.


Someone(s) did...

@Ace - Nice topic and as I love this concept itīs been interesting reading what youīve done... If you check out my tutorials you can see that I do similar things (but not so sophisticated!). Do you know of Icuurdīs "Command Stack?" Itīs another excellent set of scripts for creating and controlling FSM AI that may be of great interest to you...

AI is a thorny subject and this topic is an excellent place for intermediate users to really get to know some of the methods for creating great enemies/oponents in their games...
  • 0

U1FVsm3.png

40799.png


#10 Maarten Baert

Maarten Baert

    GMC Member

  • GMC Member
  • 750 posts
  • Version:GM8.1

Posted 25 January 2010 - 03:08 PM

The first method looks incredibly unorganized, but that's mostly because you made it look unorganized by partially copying if statement expressions. If you had used nested if statements it would have been a lot shorter.

A quick comparison:

"fake states" (very-large-switch-statement method):
[codebox]
// "standing", "ready", ... should be replaced by constants

// create
state = "standing";
wait = 0;
sprite_index = spr_standing;

// step
wait += 1;
switch state {

case "standing":
if wait=10 {
state = "ready";
wait = 0;
sprite_index = spr_standing;
}
break;

case "ready":
if wait=5 {
state = "walking";
wait = 0;
sprite_index = spr_walking;
}
break;

case "walking":
x += 1;
if place_meeting(x,y,wall_object) {
state = "bumped";
wait = 0;
sprite_index = spr_bumped;
break;
}
if wait=3 {
state = "win";
wait = 0;
sprite_index = spr_win;
}
break;

case "bumped":
x -= 1;
if wait=3 {
state = "standing";
wait = 0;
sprite_index = spr_standing;
}
break;

case "win":
if wait=10 {
state = "walking";
wait = 0;
sprite_index = spr_walking;
}
break;

}
[/codebox]
58 lines

"real states" (function pointer method):
[codebox]
// create
state = st_standing;
wait = 0;
sprite_index = spr_standing;

// step
var newstate;
wait += 1;
newstate = script_execute(state);
if newstate!=-1 {
wait = 0;
state = newstate;
}

// st_standing
if wait=10 {
sprite_index = spr_standing;
return st_ready;
}
return -1;

// st_ready
if wait=5 {
sprite_index = spr_walking;
return st_walking;
}
return -1;

// st_walking
x += 1;
if place_meeting(x,y,wall_object) {
sprite_index = spr_bumped;
return st_bumped;
}
if wait=3 {
sprite_index = spr_win;
return st_win;
}
return -1;

// st_bumped
x -= 1;
if wait=3 {
sprite_index = spr_standing;
return st_standing;
}
return -1;

// st_win
if wait=10 {
sprite_index = spr_walking;
return st_walking;
}
return -1;
[/codebox]
54 lines

There's not much difference, except you save a few 'wait = 0' lines and you can use the same functions (scripts) for different objects (in C++ I would have used inheritance for that purpose). This might be useful if the game becomes really complex, but in this case it doesn't make a huge difference.
  • 0
Posted Image

#11 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 25 January 2010 - 07:15 PM

The first method looks incredibly unorganized, but that's mostly because you made it look unorganized by partially copying if statement expressions. If you had used nested if statements it would have been a lot shorter.

There's not much difference, except you save a few 'wait = 0' lines and you can use the same functions (scripts) for different objects (in C++ I would have used inheritance for that purpose). This might be useful if the game becomes really complex, but in this case it doesn't make a huge difference.


I'm not looking at making the code 'shorter', just more manageable. The shortness is just a fringe benefit. Also, I don't use a 'pointer' method. That's obviously exactly the same as the if statements (as you also indicated with your example). In my method, the transitions happen in the states, not outside them. This allows the actual state to control itself rather than making one big set of if's or a giant switch statement to change between states. In your method there really isn't much of a difference between the 'fake' and your 'real' simply because you still have to have a state controller that is also game-specific. My method allows the states to be modular (i.e. you can copy the states and put them in another game and easily modify their behavior without touching the state controller script/code that actually changes states). If one were to do it with your method, this wouldn't be so easy and, on top of that, you'd still end up with a bunch of 'if' statements (just using a big 'switch' instead). If you actually look at the script I wrote to change states, it's not very sophisticated at all. The appeal of it happens to exist in the ability of the user to change states at will within the state itself, thus allowing the state (as an individual and as part of a group) to be both self-contained and also modular. Thanks to this, each state can be programmed independently of the object as well as the other states so that, literally, each state becomes a clean slate and can transition to any number of the others - at any time - without complicated if or switch statements.

In my system nothing is interdependent (until you require other states to complete a complicated behavior of course). Even then, since the state retains control of itself (instead of being dictated by a switch/if statement), you simply have to change a a line or two of code IN the state to negate that necessity. In your method, you need to alter both the switch statement (which will throw an error anyway if the state script it references doesn't exist, even if that state is never actually called) as well as the state code. On a small example such as the one I mentioned, it all depends on your preferences. Though, I prefer keeping things simple and organized in the GUI of gamemaker. I try only to use loose code with very simple stuff (i.e. things not dealing with complex graphics or behaviors). One thing to note is that a gui for example could be very easy to program and maintain with a Finite State Machine, but it would get complex very quickly otherwise. Since a button, for example, has nothing to do with any of the other kinds of gui elements (maybe aside from the window location), it does not need to be handled or checked alongside the states of other gui elements. That means if the button is part of a FSM, a user can always just import the button and window scripts if they only need buttons and windows, not every other part of the gui system (without having to modify the system's checking script if they don't want them, which is also provided that those scripts don't use direct script calls because you'd have to sift through tons and tons of code to find them in a full-featured gui system - then pray to whatever deity you believe in that it works without errors after you DO attempt to modify it). Thus the FSM is a very useful thing to all types of objects, not just game-specific ones. It's more than just shortening your code - it's changing how that code actually works.

The point is that FSM gives you modularity and organization with a broad element of simplicity giving you the fringe benefit of shorter code. If you like that stuff, then use FSM. If you don't, you must be a masochist. :medieval:


Do you know of Icuurdīs "Command Stack?"


Absolutely. I tried using it for this purpose before developing my system. However, it was too complex for what I needed it for. It required lots of extensions, and the command stack, though useful, was just hard to use precisely. Most of its functions could be done with state_time or other variables. Want a script to run twice in my system but no more? Check if the state_time is greater than 1, then change states using state_nextnow before executing the rest of the code to do it during the same step. You could always add 1 to a value to act as a queue and compare it to the state_time if you wanted the same functionality as his AI command stack. However, his system was probably the closest to FSM I've seen in the entire community. Though, I needed a pure Finite State Machine for my own purposes. His didn't always seem to work in the way it was supposed to; it always seemed to delay a step when needing to switch between states in the same step or it executed two states at a time. However, his was also in beta, so that's understandable. Either way, it was a very good system but I couldn't use it seriously since it really wasn't meant to be a Finite State Machine even though it behaved very similar to one.

Edited by Ace, 26 January 2010 - 05:26 AM.

  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#12 VikingAntics

VikingAntics

    GMC Member

  • GMC Member
  • 217 posts
  • Version:GM:Studio

Posted 26 January 2010 - 02:57 AM

Ace, yes, FSMs are a great way to simplify the organization of game programming. I am an old guy who was using them to write expression parsers and compilers back in the early 80s. They have infinite uses when your app requires state based processing. I am actually commenting because of your comments on Icuurds CommandStack code. There is also another system like it in the forums but I can't remember the name. They are both equally good.

I wanted to comment on the excellent benefits of Command Stack. FSM and Command Stack coexist in a game very well and each offers their own strengths and weaknesses. For AI or non interactive characters, Command Stack is ideal. Each command can have its own set of arguments local to that instance of the command. This is one of the greatest benefits. Tell the character to move to x,y and don't worry about it until it gets there. Queue multiple moves to have it patrol, each command with its own destination, speed, mode, (any arguments) and don't worry about it. All the logic and private data for that command and what to do along the way is encapsulated in that instance of the function so you don't need arrays, paths, data structures to store all of the variables for each state/move. Along the way, the unit can push another command and data, complete it, and resume where it left off. This is more cumbersome with a FSM.

Now, for my user controlled players, I personally prefer using a FSM. I want to have the player respond immediately to user input. I find Command Stack can get in the way under this situation because I am fighting with keeping the player AI and user input synchronized. The player AI could be stacking commands to execute and then the user clicks the mouse to do something different and it can be difficult to get everything back in sync. So, a FSM is easier for me to respond and change states immediately when different input is received. Since the user is in control, it is less likely that I am queuing commands. Most likely I am executing something and then waiting for more user input. Although, as always, every situation/game/programmer is different.

Anyway, I just wanted to put in my two cents. I think your explanation of FSM is very good and it was generous of you to take the time to write it and share with the community. Just wanted to say there is always room for multiple solutions. There is a funny saying that really applies to programmers, "The great thing about Standards is that there are so many to choose from!".

Maverick
  • 0

              FF_Viking-Antics_Small.png               ParticleGizmo.png


#13 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 26 January 2010 - 05:23 AM

@Maverick22:
Thanks for your comments on the Command Stack. I can definitely see its uses now. I didn't understand the necessity of the data structure extension until you mentioned the variable instancing on a per-command basis. It makes sense that it would need to store a lot of data to do that. Sorry if I made it sound too bulky in my previous post. It definitely needs that 'extra padding' to do some of it's very useful functions such as queuing multiple commands of different types and then being able to return to whatever it was your object was doing. Stuff like that is very useful in lots of situations - especially AI.

Your comments were very insightful. I hadn't even considered using both of them simultaneously in a single game before, but as you already mentioned, the two systems would actually work very well together!

Anyway, thanks again for your comments! I'm really glad you shared your thoughts on this. :)
  • 1
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#14 Maarten Baert

Maarten Baert

    GMC Member

  • GMC Member
  • 750 posts
  • Version:GM8.1

Posted 26 January 2010 - 02:08 PM

Also, I don't use a 'pointer' method. That's obviously exactly the same as the if statements (as you also indicated with your example).

A pointer is the same as an if statement?
Your scripts use script_execute, right? script_execute is more or less the same as using function pointers.

In my method, the transitions happen in the states, not outside them. This allows the actual state to control itself rather than making one big set of if's or a giant switch statement to change between states. In your method there really isn't much of a difference between the 'fake' and your 'real' simply because you still have to have a state controller that is also game-specific.

The state controller is just replacing the scripts you use.
// createstate = st_standing;wait = 0;sprite_index = spr_standing;// wait timestate_table[st_standing,0] = 10;state_table[st_ready,0] = 5;state_table[st_walking,0] = 3;state_table[st_bumped,0] = 3;state_table[st_win,0] = 10;// next state after waitstate_table[st_standing,1] = st_ready;state_table[st_ready,1] = st_walking;state_table[st_walking,1] = st_win;state_table[st_bumped,1] = st_standing;state_table[st_win,1] = st_standing;// collision?state_table[st_standing,2] = false;state_table[st_ready,2] = false;state_table[st_walking,2] = true;state_table[st_bumped,2] = false;state_table[st_win,2] = false;// next state on collisionstate_table[st_walking,3] = st_bumped;// spritestate_table[st_standing,4] = spr_standing;state_table[st_ready,4] = spr_ready;state_table[st_walking,4] = spr_walking;state_table[st_bumped,4] = spr_bumped;state_table[st_win,4] = spr_win;// stepwait += 1;if state_table[state,2] and place_meeting(x,y,wall_object) {wait = 0;state = state_table[state,3]} else if wait==state_table[state,0] {wait = 0;state = state_table[state,1];}sprite_index = state_table[state,4];
I'm not saying it's a good method (it's very limited obviously), but it's a FSM too.

The only way to write code that's not a FSM is something like this:
// createwhile(true) {sprite_index = spr_standing;repeat 10 {io_handle();screen_redraw();sleep(10);}sprite_index = spr_ready;repeat 5 {io_handle();screen_redraw();sleep(10);}sprite_index = spr_walking;collision = false;repeat 3 {x += 1;if place_meeting(x,y,wall_object) {collision = true;break;}io_handle();screen_redraw();sleep(10);}if collision {sprite_index = spr_bumped;repeat 3 {x += 1;io_handle();screen_redraw();sleep(10);}} else {sprite_index = spr_win;repeat 10 {io_handle();screen_redraw();sleep(10);}}}

Your implementation is good, but it's not the only way to use FSMs :).

EDIT:

Besides that, thinking in terms of automata (that is, breaking the execution process down to automaton steps and passing information from step to step through the explicit state) is necessary for event-driven programming as the only alternative to using parallel processes or threads.


Edited by Maarten Baert, 26 January 2010 - 02:17 PM.

  • 0
Posted Image

#15 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 26 January 2010 - 08:42 PM

@Maarten Baert
Oops. Sorry for my assumption on your code. I only glanced over your 'fake' states quickly and assumed the second one was all in the step event as well and simply pointing at different scripts one by one with script_execute since the scripts didn't appear to be separated at first glance and I only saw the "//create" and "//step" parts when I looked over it. I just assumed that by your "pointing" method you meant manually "pointing" at the scripts with if statements when they had to be executed. Sorry about that. I was in a rush when I looked over your code, but you're definitely right.

This definitely isn't the only way to do FSMs for sure, but I've found it to be a pretty useful system in general as far as programming action or fighting style games both quickly and easily goes, especially for beginners who aren't comfortable in programming-based environments, where the slightest hint of a nested if statement or for loop gives them nightmares. As long as they know the commands to change sprites, move an object, and deal with a collision in some way, they should be able to do just about anything they want with this system. All they need is one script, a couple of commands, and some creativity.
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#16 Memode

Memode

    GMC Member

  • New Member
  • 61 posts

Posted 31 January 2010 - 03:00 AM

Well this certainly looks like a great method, I for one have been using masses of switches of if statements that are getting all mucked up, and state machines sounds like what I should be doing.

But I'm finding this still a little overwhelming. It just looks like a state holds a bunch of if statements of anything that might happen. How is this more efficient? What if you had a complex movement/physics system, wouldn't it require a million if statements for each state?

Is this just another way of laying things out into a more ordered fashion then, or do I just not get it? :whistle:
  • 0

#17 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 31 January 2010 - 03:50 AM

What if you had a complex movement/physics system, wouldn't it require a million if statements for each state?


Not at all. If you look at the Zero Engine in my example, I run my (very complex) physics system only once. Then, I just run the state machine afterwards. This isn't just a while loop. Each state happens as long as it needs to happen and then you either go to another state in the current step (which is very useful to keep the physics the same while doing so) OR do it in the next step, allowing the physics system to kick in its code again in the step event and then, afterwards (in the next step that is) it will run the finite state machine again (and then the physics system if you have one there). During the state itself, however, nothing needs to happen except exactly the code that needs to be executed during that state.

Though, if you have a physics system that needs to be disabled while in a state, simply use a CTRL variable and then run the physics script ONLY if that CTRL variable is true. That is, if the physics system has control and the character is able to move, then CTRL is true, but if the state needs control of the physics (for a flying uppercut for example), you simply set CTRL to false and the physics system will no longer activate until you set CTRL to true again when you finish your movement (which is probably when you decide to change states during that state OR when you reach the final state of the overall movement requiring special physics). If you don't understand, look at the megaman object in that Zero Engine example (particularly his st_dash() script) to see how to disable the physics system (which consists of the zero_physics()/zero_controls()/zero_platforming() scripts in each object's step event) in case you need a concrete example on this.

Just to answer your other questions, this is not simply a method of laying stuff out more orderly. It is more efficient simply because each state is how an object must 'exist' at that given point in time. It must behave in a certain way while in certain states. For example, if you're in a st_seekobject state, you would want to move toward an object, but only during that state. If you find that object, you might want to change to an attacking sprite and thus you may want to use another state that does not run the move_towards_object script and simply keeps the sprite as an attacking sprite until the animation ends. If that other object moves in the meantime, your object won't move while in an attacking state such as st_attackobject. However, if you have to interact with a physics system that's too complex for a few scripts in the step event, you need to run whatever physics scripts you're in need of at whatever moment you need them. This too would be handier using states. However, if you use something such as a jump and still need to move left or right, you might simply want to make a more general state such as a st_movement state to tell whether or not the player is moving left/right or jumping and change sprites accordingly in that state (i.e. check if the ground is beneath him or if the player has a positive or negative hspeed and vspeed in order to find the proper left/right/jump/fall/stand sprite). Since this isn't a 'special' state such as an attack, it doesn't need its own state. Though, if you have attack sprites for those, DO change to a new attack state that simply uses the st_movement code, except, instead of changing to the normal movement sprites, you put the attack animation sprites in their place during that state. Then check (during that state) if you're on the last subimage of the animation sprite and change back to your normal movement state.

Edited by Ace, 31 January 2010 - 04:24 AM.

  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#18 Memode

Memode

    GMC Member

  • New Member
  • 61 posts

Posted 31 January 2010 - 05:56 AM

Thanks Ace, I will study this because it is clearly worth it :whistle:
  • 0

#19 Guest_SenileFrog_*

Guest_SenileFrog_*
  • Guests

Posted 31 January 2010 - 09:00 AM

Ace,

Would you mind making, say, a text or PDF file to go with the Zero Engine so that people (especially newbies like me) can come to grips easier with your code?

It is a LOAD to read through.

Nice work though, it's awesome. :whistle:

#20 jabelar

jabelar

    GMC Member

  • GMC Member
  • 3003 posts

Posted 02 February 2010 - 12:35 AM

Yes, this is exactly the method I use -- I have a variable called state, processed once per step, with transitions to new states based on "inputs" (user inputs or game conditions).

The most important thing about this method is that it makes sure you handle every situation. Like what happens if you are ducking and try to shoot? What happens if you are jumping and try to duck? And so on. In most people's programming style, they program it all as some complicated set of if statements and make mistakes such that weird glitches occur for states that aren't handled.

So the most important thing is that it ensures every situation is handled appropriated.

It also makes it really easy to debug. If something glitches while the character is jumping, then the bug must be in the code that handles the jumping state. I don't have to trace through all my code, but can skip quickly to where the problem is.

Glad you took the time to explain this.

By the way, in semiconductor engineering (my field of expertise), all digital logic circuits are developed using state machine method.
  • 0

#21 Millennial Phungus

Millennial Phungus

    GMC Member

  • GMC Member
  • 278 posts
  • Version:Unknown

Posted 02 February 2010 - 04:55 AM

I've been playing around with this for a while now and found that I had one more command that I had to add in addition to the four original ones, this was state_return. Basically it's like state_next but it returns to the state right before the current state was activated and at the same state_time position it left off at. This was useful because sometimes I wanted to go back to a state but not start it over (like if I wanted someone to wave, halfway through the wave do a jump, then when he lands resume the wave right where he left off).

I must say, FSMs are really nice for debugging. A lot easier than if statements at any rate.
  • 0

Insert witty signature here.


#22 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 02 February 2010 - 07:15 AM

I've been playing around with this for a while now and found that I had one more command that I had to add in addition to the four original ones, this was state_return. Basically it's like state_next but it returns to the state right before the current state was activated and at the same state_time position it left off at. This was useful because sometimes I wanted to go back to a state but not start it over.


That's actually really handy. You wouldn't mind sharing your updated script would you? I'm sure I could do it pretty easily, but if you've already got it working well, it would be a pretty nice addition to the state script. I was actually planning to update the state script to support arguments a little better (i.e. passing them to one another more easily and resetting them upon changing states). Since you've added a useful feature to yours, I wouldn't mind basing the better argument system on your state script modification if you don't mind sharing it.
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#23 Millennial Phungus

Millennial Phungus

    GMC Member

  • GMC Member
  • 278 posts
  • Version:Unknown

Posted 03 February 2010 - 01:52 AM

Here's what I used for state_return. If you see something that can be streamlined, feel free to point it out.

I added these variables in the Initialize portion of the state_machine script:
state_time = 0; //time we've been in the current state
prev_state_time = 0;
state_return = 4; //returns to the previous state with the previous time

And then in Process State Transitions I went to each command which changed the actual state rather than repeating it (state_next, state_nextnow, and state_return) and saved state_index to prev_state before changing state_index. Same thing for state_time to prev_state_time.

I then added the command for state_return after state_continue.

//Process State Transitions
var nxt;
nxt = script_execute(state_index);

while(nxt == state_repeat) //repeat state but don't go to next step
{
  nxt = script_execute(state_index);
  state_time += 1;
}
while(nxt == state_nextnow) //go to next state during this step
{
  prev_state = state_index;
  state_index = next_state;
  prev_state_time = state_time;
  state_time = 0;
  nxt = script_execute(state_index);
  
  if(nxt == state_repeat)
	script_execute(state_machine);
}
if(nxt == state_next) //change state in the next step
{
  prev_state = state_index;
  state_index = next_state;
  prev_state_time = state_time;
  state_time = 0;
}
if(nxt == state_continue) //continue state in the next step
{
  state_time += 1;
}
if(nxt == state_return) //new command I added
{
  var temp_time;
  
  prev_state = state_index;
  state_index = next_state;
  temp_time = prev_state_time;
  prev_state_time = state_time;
  state_time = temp_time;
}

To call state_return, use:

next_state = prev_state;
return state_return;

Not exactly the smoothest code, but it works (barring any undiscovered script breaking bugs).
  • 0

Insert witty signature here.


#24 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 03 February 2010 - 04:03 PM

Thanks for sharing your code! I looked over it and saw a few things that may could be simplified a bit, but after thinking on it, I doubt it could retain the specific behavior you gave it if I were to add it to the engine by default. However, returning to the previous state (without restoring the state time) would be a great addition useful to everyone.

I initially planned it but never actually implemented it because I was unsure of how I wanted the default behavior of the state_time variable to be. However, you could always pass the state_index of the previous state as arg0 and the state_time as arg1 and then reset them to 0 in the previous state after returning to it. I have already added automatic resetting of the arg values in the new version of the script, so resetting the arg variables is just a temporary necessity until I release the next update on the Zero Engine scripts in a couple of days.
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#25 js_123

js_123

    GMC Member

  • New Member
  • 41 posts

Posted 05 February 2010 - 01:09 PM

its interesting one...........keep doing ur work...........all d best
  • 0

#26 peter john

peter john

    GMC Member

  • New Member
  • 18 posts

Posted 05 February 2010 - 06:03 PM

Gud one............but coding is really tough to understand!
  • 0

#27 badger_tycoon

badger_tycoon

    GMC Member

  • New Member
  • 3 posts

Posted 13 February 2010 - 08:15 PM

i'm interessed to learn to do this, but cant make heads or tails of
nxt = script_execute(state_index,arg0,arg1,arg2,arg3,arg4,arg5,arg6
,arg7)
while(nxt == state_repeat)
etc...
in "state_machine" What does state_repeat mean?? Repeat the state, but where does it come from?

Im on lite so cant change the constants. You explained that "state_continue, state_repeat, state_nextnow and state_next" should be defined as constats. What do they mean/stand for?


In your example, part of st_defualt reads
image_single=0 //set our image to the circle subimage

//Change to Square (I also label my state transitions)
if(input_check(ev_button1)>0) { //if we just pressed input button 1,
  next_state=st_square //set the next state.
  return(state_next) //stop script here and go to the next state in the next step
  }

so the next state is "st_square", but then "state_next" is returned. What does that do? How does that change the state to "st_square"?

I understand that i may just be a newbie lite user, and the answer may be easy. But i do want to learn to use this, it seams an easier method of coding than i have used before.

if your wondering why i dont just use your engine as is, i like to try and rewrite simpler(noobier if you will) versions of code that i understand and can use how i like. Your whole example confuses me as a whole :)
  • 0

#28 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 14 February 2010 - 06:50 AM

In the part you're referring to, state_repeat is obtained from the script being executed. I won't go into details because if you don't quite get it as is, it really doesn't matter anyway because you'll never need to touch the script to use it.

As far as the state example goes, however, I can see why this confuses you. What you're probably overlooking is that the script itself doesn't physically change the states. It returns a value which is then read by the state_machine() script and it gets changed there or simply gets repeated again in some way. When you return the state_continue value the state will be repeated the next step of the game, but when you return the state_repeat value, it repeats the state during that step once more and thus no other step of the game happens until you're done making it repeat (making this work kind of like a while loop).

Basically, the st_default script in the example continuously checks for Button 1 to be pressed. If it is pressed, then it sends a message to the state_machine() script in the step event telling it to change to the st_square state in the next step of the game (when the step event is run again, thus running the state_machine() script again). Therefore, no state is changed until the state_machine() script is executed (unless you do it yourself directly with the state_index variable, which is very useful sometimes for interactions with enemy or power-up objects for example that have no access to the return values in the current state (such as state_continue, state_repeat, etc). The return values only exist to talk to the state_machine() script, telling it in what way states should be transitioned or whether they should stay the same.

Also, that next_state variable simply tells the state_machine() script what the next state should be just before you make the state_machine() script transition us to it by returning state_next value (which also talks to the state_machine script).

So, in a nutshell, all your state scripts should do is tell the state_machine() script how to go (by using the return values) and when and where you actually want to go. And, just fyi, after the return() part is executed, no other code happens in that state after this is called.

Finally, as for writing a simpler version of my state_machine script, there really isn't one unless you want to get rid of the argument functionality or something. Feel free to modify it for your own purposes, but be careful not to break it. :)
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#29 oblivion2112

oblivion2112

    GMC Member

  • New Member
  • 4 posts

Posted 15 February 2010 - 03:56 AM

Wow, :) This is the best game engine I have ever seen! 5/5 Once you get some nice sprites, putting together all the animations into an object is a piece of cake. Thanks, dude, I love you for this :P
  • 0

#30 Tumetsu

Tumetsu

    GMC Member

  • New Member
  • 433 posts

Posted 15 February 2010 - 04:30 PM

This seems like a very interesting mechanic. I read the article and downloaded the example but I haven't played with it yet so forgive me if my questions are bit dumb (I don't have time right now to actually play around with engine).

I think I got the point of the system especially with complex animations. Let's say that I have 4 different animations for a certain character (let's say it's NPC). One would be idle animation, second walking, third surprised and fourth angry animation. Should I create state for each of these animations and how should I handle the changing between states when current animation ends? Should I just calculate steps it takes for each animation to play through or can I use "Animation End" event or perhaps somekind in state checking?

After quickly looking to your example, I would like to know which scripts are needed to exported to my own purposes?(as I like to test this in my own environments without all that extra stuff complicating the learning process) Am I right that basically "state_machine" is only needed script (along with needed st_scripts of course) in case I want to use the method with uncontrollable character's animation and moving?

Thanks. I will check this later more precisely when I have enough time to immerse myself to this ;)
  • 0
Posted Image

#31 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 16 February 2010 - 04:02 AM

Wow, ;) This is the best game engine I have ever seen! 5/5 Once you get some nice sprites, putting together all the animations into an object is a piece of cake. Thanks, dude, I love you for this ;)


Haha! I'm glad you like it dude! I designed it that way for people like me who just want to throw some art in a game and not have to worry about the complexities of if statements and a load of variables to make stuff behave the way you want it to.


Let's say that I have 4 different animations for a certain character (let's say it's NPC). One would be idle animation, second walking, third surprised and fourth angry animation. Should I create state for each of these animations and how should I handle the changing between states when current animation ends? Should I just calculate steps it takes for each animation to play through or can I use "Animation End" event or perhaps somekind in state checking?


Speaking of game art and your RPG style game stuff, I am actually working on an RPG example right now so if you want to wait for specifics, you can. However, to answer your question in terms of what I would do, I would create two states first. One state to check for the "hsp" and "vsp" values for all the different directions and set the sprites according to those values in one main state. Next, for any animations that need "Animation End" stuff I would make a state specific to those and use the "animation_end()" script to check if you're on the end of the animation (no need to use a separate event) and return to the main state by setting its script as the next_state and then using return(state_next) to go there. There is also the state_time variable that increases by 1 each step automatically and resets to 0 when you change states. You can use that to check for a certain number of steps before you change back to the main state. This is useful for single frame animations for example.

I know you haven't asked, but if you wanted an NPC to move along a certain path, you could make a state that sets an actual path when it's state_time is 0 and stays in the state until that path's position is >= 1. At that point in time, that state can be changed to some other state that could possibly show some dialogue or change rooms. You can easily program RPG events this way using GM's built-in path editor with an image of the room as a background. It is a great feature when used in conjunction with states. :)

I would like to know which scripts are needed to exported to my own purposes?(as I like to test this in my own environments without all that extra stuff complicating the learning process) Am I right that basically "state_machine" is only needed script (along with needed st_scripts of course) in case I want to use the method with uncontrollable character's animation and moving?


I've given you some insight on how to do movement with states just now, however, as for the other scripts, I really wouldn't remove anything aside from the actual "states" folder and maybe the Zero Image scripts. You'll likely want to keep the entire Zero Plus folder otherwise, though. There are many many useful things in there for RPGs as well as the zero_motion() and Zero Input section of scripts. It is MUCH better to learn the entire engine at once than it is to learn only parts of it at a time because they are all designed to fit together. I advise learning all the scripts used in the example objects (objP1, mario, & goomba) before hopping in on your own. I think those should give you a pretty fair idea of what's happening. The only weird thing about objP1 is that it is also using the RPG room's physics when it is in that room. The megaman object shows how to use the inventory system (odd, I know, but I wanted to keep the objects as simple as possible by not cramming too much into any one in particular). Learn each of the objects and you should have the basics of the engine down in no time. However, if you try to hop in on your own, chances are you'll overlook something important or just very useful. When you understand how the objects work a bit, only then do I feel you should actually be ready to hop in and make your own. All of the scripts I've provided (aside from the drawing ones) have been designed to work well with states (including the physics engines, which you will see when I release my updated version in the next day or so).
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#32 Tumetsu

Tumetsu

    GMC Member

  • New Member
  • 433 posts

Posted 16 February 2010 - 09:05 AM

Thanks for your response! It clarified things a bit more :D Actually I'm not going to make RPG (more like point 'n click adventure) so that example was completely hypothetical. I would like to use this method for complex animations with several frames and paths. I have been looking somekind "animation engine" sometime and this seems to fitting to my purposes. That's why I'm mostly interested in animating stuff with this (though I understand it's usability in other aspects as well). Now I have some extra time so I will dive deeper to this and look your scripts through with more thoughs. So expect some further questions in near future :D

And btw, I suggest that you would do somekind very basic step by step tutorial for doing a simple statemachine object (kind like your standing, walking, bumping, pose example) where user can still code it themselves like GM's basic tutorials. I think it could be useful as many people learn this stuff better by actually doing it themselves with helpful guidelines.

EDIT: After examining your input scripts I have to ask does this support mouse input? Currently I can't seem to find anything mouse related in your scripts.

EDIT2: I really have to say that I'm impressed from the tools you have offered for use in this engine. I'm getting more and more convinced that I could really have real use for some of the features. Continuing the exploring :)

Edited by Tumetsu, 16 February 2010 - 09:52 AM.

  • 0
Posted Image

#33 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 18 February 2010 - 05:30 PM

I think this is exactly what I didn't realize I was looking for to resurrect one of my 'dead' projects that just got too complicated and too bogged down and buggy last year.

I'm obviously stuck on something embarrassingly noobish and obvious but I can't figure it out. I've got the state machine running in the step event of the player object (objPlayerShip) like this: I want to pass the object as an argument because the st_physics scripts will apply to multiple things, not just the player (but st_controls only applies to the player.)

state_machine(    st_physics_init(objPlayerShip),st_controls_init);

these init scripts set their state_next values to st_physics_motion and st_controls_player respectively, and so far so good. But then I get an error in those scripts:

ERROR in
action number 1
of Step Event
for object objPlayerShip:

In script st_physics_init:
In script st_physics_motion:
Error in code at line 14:
return(state_continue);
^
at position 9: Unknown variable state_continue


st_physics_init (kind of long):

st_physics_motion, for reference, looks like this (both of the scripts end the same way:)

with(argument0){    facing_direction = (facing_direction+spin) mod 360;    image_angle = facing_direction;    momentum = abs((speed*mass)*1); // keep momentum a positive value}// remain in this statereturn(state_continue);

Since this is my first implementation of a fsm (although I got this code to work 'the old way'), I'm still in the 'see what he did with zero engine and copy it' stage, but as far as I can tell this should be correct? What am I missing?

Edited by k5000, 18 February 2010 - 05:31 PM.

  • 0

#34 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 18 February 2010 - 09:38 PM

I've tinkered a bit and now I'm getting an error in state_machine itself:

ERROR in
action number 1
of Step Event
for object objPlayerShip:

In script state_machine:
Error in code at line 72:
while(nxt == state_repeat) { //repeat state but don't go to next step
^
at position 15: Unknown variable state_repeat

  • 0

#35 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 18 February 2010 - 10:25 PM

Well, the only issue you've got there is that you're trying to be in two states at once initially. That is, you're trying to initialize 2 states at once.

However, the reason it's called a "finite" state machine is that the number of states an object can be in is "finite", or in other words, just one.

That means, when you call the state_machine() script, you aren't doing anything but entering the first state (however, in the subsequent steps, you will simply continue on the state you left off last in with state_continue), which can be either of the initialization scripts, but only ONE of them at a time. If you want both to be executed, you have to transition from one to the next using state_nextnow (to do all the initialization during the same step).

Also, a state machine is local to a single object. That is, it only runs in the object it is assigned to. If you want a script to be run as if it were in another object, you would need to put "with(object_to_run_in){script code}" in the state script that is to be run. It's better to give each separate object its own state machine script though. The ship, for example, should run its own initialization scripts if possible, and then transition to the state_physics_motion script. From then on, it should either use a return(state_continue) to continue running the physics script each step, or transition from it to a death state (for example) if the ship is destroyed, which should check for the animation_end() with the respective script and restart the room or create a new ship or something. Hopefully that gives you some idea on what you're doing wrong. You just need to realize that states are linear. In any script you can go to many different states, but you can ultimately only go to ONE. The rules simply check for what state to go to next during a script, and if you don't go to any other state, you just return(state_continue) at the end of the script. If you want to run multiple states simultaneoulsly, you can, of course, use two state machine scripts at once, but I'd strongly advise against it. Instead, I would just run the necessary physics script (after the state machine initialized it) in the step event itself. That way, you'll call the state_machine script first, which transitions to all the other initialization scripts and finally a state that it settles in which continues to repeat indefinitely with state_continue, and THEN the physics script will be run in the step event after the state_continue variable is returned (since that means that the state transitions are done for this step and will continue again in the same state the next step, running that script again until state_continue is called once more, then the rest of the step event is run again, etc, etc, etc).

Also, you might want to set some constants for the variables if you plan on running state scripts in other objects so all objects know about the return values such as state_continue (even without a state machine script of their own). However, I would still advise against using a single object setting the states in other objects. Each object should be able to control itself for the most part, and only in special cases should other objects interfere. It kind of defeats the purpose of a state machine otherwise, adding lots of unnecessary complexity. The 'controller' obj might as well be the state machine in that case, which is kind of pointless since it doesn't natively do transitions.

EDIT:

That error, btw, only happens when you don't add a return(state_transition) to a script you've transitioned to.

Edited by Ace, 18 February 2010 - 10:40 PM.

  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#36 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 18 February 2010 - 11:54 PM

I understand. I've created a 'st_physics_init' script to run first, which sets all the variables and then transitions to st_physics_motion, which continues. I'm still getting the error where it doesn't recognize state_next in that script (which makes me think it's not even calling state_machine at all) so there's something wrong still, clearly... but I wasn't getting the linearity of it. Thanks for the help.
  • 0

#37 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 19 February 2010 - 04:30 AM

I understand. I've created a 'st_physics_init' script to run first, which sets all the variables and then transitions to st_physics_motion, which continues. I'm still getting the error where it doesn't recognize state_next in that script (which makes me think it's not even calling state_machine at all) so there's something wrong still, clearly... but I wasn't getting the linearity of it. Thanks for the help.


You're very welcome. As for your state_machine problem, post the code you have now for the motion script and I'll take a peek at it for you. I wouldn't recommend calling state_next without using the next_state variable first though. If you're using the state_continue transition don't set the next_state variable during that script unless you're doing it just before going somewhere else with state_next. Do realize, however, that as soon as you call return() for anything, it exits your code exactly on that line and nothing else is processed after that. So if any of your scripts return() anything (other than state transition values) that could be exactly your problem. However, without your code I don't really know for sure what your problem could be unless you're just not returning a transition type for some reason. ALL state scripts must return(state_transition) no matter what. If you're not doing that at the end of your physics script (or any of the others for that matter), there will always be that error eventually, even if it appears to be running fine at first.
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#38 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 19 February 2010 - 05:05 AM

Here's the entire code... the crazy thing is it works if I take it out of the state machine entirely and just run it in the step event without the return statement at the end. This is a space shooter with zero-g physics so all this script does is update the sprite angle and the momentum variable... this is the 'free flight' state (there will also be a state when colliding with objects of the same type and one when 'tethered' to them, so you can move things around... in each case the physics are a bit different.)

___________________________________________facing_direction = (facing_direction+spin) mod 360image_angle = facing_directionmomentum = abs((speed*mass)*1) // keep momentum a positive valuereturn(state_continue)

And I get:


___________________________________________
ERROR in
action number 1
of Step Event
for object objPlayerShip:

In script st_physics_motion:
Error in code at line 5:
return(state_continue)
^
at position 9: Unknown variable state_continue

  • 0

#39 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 19 February 2010 - 06:11 AM

All I can guess as I've looked through your code is that you're doing something weird with the object actually executing the sate such as making it execute code in some other object without a state machine OR you just need to use something like the following in the motion script (instead of returning state_continue):

next_state = st_physics_init 
return(state_next)

The state_next will also wait until the next step and go back to the previous branch of physics in the physics init script to check for collisions, etc., or continue on its merry way. Basically, it seems like it needs to return to the previous state for the next step of the game to check for collisions again. However, more than your code, I need to know exactly the flow of the scripts you're trying to use and what you're trying to accomplish in each. Try making constants, too, for all four of the state transitions. This should help fix any weird object-related issues since constants are known globally.
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#40 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 19 February 2010 - 04:39 PM

Alright. I've taken out all the state scripts, all the control stuff, everything except two dummy states, st_does_nothing and st_also_does_nothing. This way I can find the little nitpicky thing that has to be wrong here.

st_does_nothing sets a variable (p=0) and loads the next state with a return state_next,. st_also_does_nothing sets p=1 and continues its own state. It now freezes the game on load. I've tried declaring state_previous,state_next,state_continue (etc) as global constants, and that caused the game to crash immediately (setting them to either 0 or 1.) Once, I managed to get it to give me the 'unknown variable' error but I seem to be past that now.

So, I thought, maybe I'm using an old version of the state machine and I just don't realize it? So I downloaded the zero engine again and passed the state_machine script (which had the same number of lines as the one I was using, so it was probably the same) with no luck.

Anyway, I'll keep working on it.

(one last edit to point out that I had a link to the file up, but the problem's since been fixed, so that's gone.)

Edited by k5000, 20 February 2010 - 05:21 AM.

  • 0

#41 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 20 February 2010 - 03:00 AM

The constants must have these values. They won't work without the proper values.

//Return Actions (These are defined as constants already in this example)
 state_nextnow  = 3 //execute the next state during this step
 state_next	 = 0 //execute the next state in the next step
 state_continue = 1 //continues a state again next step
 state_repeat   = 2 //repeat this state again THIS step

  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#42 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 20 February 2010 - 05:18 AM

That's what I missed! I added those constants with those values (and thought to check the actual zero engine file and, yep, there they were) and it works like a charm now. Thanks. :)
  • 0

#43 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 05 April 2010 - 08:33 PM

Alright another 'what am I doing wrong' question...

I'm converting my objects to use the state machine. I have (just to use an example) my player object ObjPlayer, which sets up a load of variables in the create event, with these important variables (even though they're all special snowflakes in their own way:)

crosshairs_x=x;
crosshairs_y=y;
aim_direction = direction;

to hold the x and y position and angle of a crosshairs sprite. the position is changed in the step event (which I don't remember the code to offhand but it doesn't matter -- the important part is that those three variables get updated) and in the draw event we have:

// draw player sprite

draw_sprite_ext(
 sprite_player,
 sprite_player,
 x,
 y,
 1,
 1,
 direction,
 c_white,
 1
);

// draw crosshairs

draw_sprite_ext(
 sprite_crosshairs,
 sprite_crosshairs,
 crosshairs_x,
 crosshairs_y,
 1,
 1,
 aim_direction,
 c_white,
 1
);

Now all that works just fine using scripts without the state machine -- and with the state machine only if I have that first script in the create event. But when I try to change that first script into a state script (st_player_init or whatever) then I get start getting errors that those variables can't be found.

So I guess my questions would be:

Is it any huge deal just running an init script in the create event anyway? I don't know if the state machine is designed to run optimally with all the object code (except the draw event code) inside that, or if it matters, in terms of speed and efficiency. The way I look at it if I'm running a create script and a draw event script for each object anyway why use the state machine to begin with? Just for AI?
  • 0

#44 Ace

Ace

    GMC Member

  • GMC Member
  • 372 posts

Posted 06 April 2010 - 08:57 AM

Well, a state machine can be useful for many reasons. The most typical reason is if you want different kinds of behaviors for an object at different times. AI, sprite display, or even game logic and/or menu systems can use a state machine. It's also possible to use the state machine in the drawing event itself (if you want to do state based drawing). This would very much work for a simple menu system for example that might display cool pop in graphics that twirl or rotate to some sort of new position.

Behaviors can be done many ways, but the most common is to have a script that acts as a state controller and reroutes state execution to the most necessary event. This is best done in objects with AI or just complex interactions between states (i.e. go to the state that sets sprites, set an arg to 1 and return to the state controller. If that arg is true, go to the state that sets physics and set them, resetting the arg value with the "argument_clear" variable).

As for initialization, the only reason I used a state_machine(st_init) style state script in the example was to show that it is possible to make objects modular. That is, an object with the behavior of mario could use a st_luigi_init() script to modify the sprites or physics variables in a luigi character object by calling the new state_luigi_init() script in a luigi object's state machine.

The new RPG versions of the Zero Engine shows a few examples of states being initialized using the state_machine script in the create event instead of the step event and then called again in the step event, but without any need for the default state argument supplied (since it has already been initialized). As long as it was already called once in the create event, it doesn't need an argument in the step event when you call the state_machine() script. It will look just like I wrote it in the previous sentence while in the step event if the default script was already called in the create event in the form state_machin(st_init) or whatever (which is what you likely need to do for now to solve your local variable errors).
  • 0
Posted Image Posted Image Online Fighting & Roleplay Game

ZERO ENGINE
Posted Image

#45 iVix

iVix

    GMC Member

  • New Member
  • 20 posts

Posted 06 April 2010 - 03:45 PM

___________________________________________
COMPILATION ERROR in Script: rpgmaker_char
Error in code at line 29:
newspr = sprite_create_from_screen(0,0,w,h,0,1,0,0,w/2,h/2)
^
at position 60: Wrong number of arguments to function or script.
  • 0

#46 Khelder

Khelder

    GMC Member

  • GMC Member
  • 2301 posts
  • Version:GM:Studio

Posted 06 April 2010 - 03:47 PM

They changed that function in GM8 iVix, removing an argument. Change "1,0,0" to "1,0"
  • 0

#47 k5000

k5000

    GMC Member

  • New Member
  • 248 posts

Posted 06 April 2010 - 05:30 PM

Well, a state machine can be useful for many reasons. The most typical reason is if you want different kinds of behaviors for an object at different times. AI, sprite display, or even game logic and/or menu systems can use a state machine. It's also possible to use the state machine in the drawing event itself (if you want to do state based drawing). This would very much work for a simple menu system for example that might display cool pop in graphics that twirl or rotate to some sort of new position.

Behaviors can be done many ways, but the most common is to have a script that acts as a state controller and reroutes state execution to the most necessary event. This is best done in objects with AI or just complex interactions between states (i.e. go to the state that sets sprites, set an arg to 1 and return to the state controller. If that arg is true, go to the state that sets physics and set them, resetting the arg value with the "argument_clear" variable).

As for initialization, the only reason I used a state_machine(st_init) style state script in the example was to show that it is possible to make objects modular. That is, an object with the behavior of mario could use a st_luigi_init() script to modify the sprites or physics variables in a luigi character object by calling the new state_luigi_init() script in a luigi object's state machine.

The new RPG versions of the Zero Engine shows a few examples of states being initialized using the state_machine script in the create event instead of the step event and then called again in the step event, but without any need for the default state argument supplied (since it has already been initialized). As long as it was already called once in the create event, it doesn't need an argument in the step event when you call the state_machine() script. It will look just like I wrote it in the previous sentence while in the step event if the default script was already called in the create event in the form state_machin(st_init) or whatever (which is what you likely need to do for now to solve your local variable errors).


I see, thanks. This method has already been a big help and it's good to know I don't have to implement it 'halfway.' I never thought to check the rpg example because, well, i'm not doing an rpg. But getting enemy ai and ui elements running is already tons easier.

I was also apparently a couple of versions behind on the zero engine, so I updated that too.
  • 0

#48 SparkzBolt

SparkzBolt

    Graphics....Zap

  • New Member
  • 416 posts
  • Version:Unknown

Posted 10 April 2010 - 12:53 AM

There is a error the instant I run it. I did not modify it in any way.
  • 0
I'm back.

#49 Rani_sputnik

Rani_sputnik

    GMC Member

  • GMC Member
  • 482 posts
  • Version:GM:Studio

Posted 14 April 2010 - 05:56 AM

Dude, thank you! I am gonna base my entire game on this principle it is that good.
(I used to be one of the people that used 'fake states' *sheepish grin* )
  • 0

My games - In DecemberBoy Goes to Space

Utilities & Extensions - FloxGM, Destroyable Terrain

Check out my website: ryanloader.me, or follow me: twitter.com/RaniSputnik


#50 brod

brod

    Brian RODriguez

  • GMC Member
  • 2050 posts
  • Version:GM8

Posted 14 April 2010 - 02:15 PM

You know timelines are pretty much Game Maker's equivalent to FSMs. Here's an adapted version of your first, "messy" code using timelines.

TIMELINE:
STEP 1
  sprite_index = spr_standing;

STEP 11
  sprite_index = spr_ready;

STEP 16
  sprite_index	  = spr_walk;
  hit			   = 0;
  retry			 = 3;
  timeline_position = 18;

STEP 18
  if(place_meeting(x+1, y, wall_object)==false) {
	x	+= 1;
	retry-= 1;
	if(retry>0)timeline_position-=1;
  } else {
	sprite_index	  = spr_hit;
	hit			   = 1;
	timeline_position = 20;
  }

STEP 20
  if(hit==1) {
	if(retry<3) {
	  x				-= 1;
	  retry			+= 1;
	  timeline_position-= 1;
	} else {
	  timeline_position = 0;
	}
  }

STEP 21
  sprite_index = spr_win;

STEP 31
  timeline_position = 0;

What's even cooler about timelines is that you can also set speeds for it, and no steps would be skipped. You can even pause and continue them whenever you want. Very very useful stuff.

Edited by brod, 14 April 2010 - 02:32 PM.

  • 0