In Panda3D, FSM's are frequently used in game code to automatically
handle the cleanup logic in game state changes. For instance, suppose
you are writing a game in which the avatar spends most of his time
walking around, but should go into swim mode when he enters the water.
While he is walking around, you want certain animations and sound
effects to be playing, and certain game features to be active; but
while he is swimming, there should be a different set of animations,
sound effects, and game features (this is just an example, of course):
Walk state
- Should be playing "walk" animation
- Should hear footsteps sound effect
- Collision detection with doors should be active
|
Swim state
- Should be playing "swim" animation
- Should hear underwater sound effect
- Should have fog on camera
- Should have an air timer running
|
So, when your avatar switches from walking to swimming, you would
need to stop the footsteps sound effect, disable the door collisions,
start playing the "swim" animation, start the underwater sound effect,
enable the fog on the camera, and start the air timer.
You could do all this by hand, of course. But using an FSM can
make it easier. In this simple model, you could define an FSM with
two states, "Walk" and "Swim". This might be represented graphically
like this:
To implement this as a Panda3D FSM, you would declare an new class
that inherits from FSM.FSM, and within this class you would define four
methods: enterWalk(), exitWalk(), enterSwim(), and exitSwim(). This
might look something like this:
from direct.fsm import FSM
class AvatarFSM(FSM.FSM):
def __init__(self):#optional because FSM already defines __init__
#if you do write your own, you *must* call the base __init__ :
FSM.FSM.__init__(self,'avatarFSM')
##do your init code here
def enterWalk(self):
avatar.loop('walk')
footstepsSound.play()
enableDoorCollisions()
def exitWalk(self):
avatar.stop()
footstepsSound.stop()
disableDoorCollisions()
def enterSwim(self):
avatar.loop('swim')
underwaterSound.play()
render.setFog(underwaterFog)
startAirTimer()
def exitSwim(self):
avatar.stop()
underwaterSound.stop()
render.clearFog()
stopAirTimer()
myfsm = AvatarFSM()
|
Keep in mind this is just an imaginary example, of course; but it
should give you an idea of what an FSM class looks like.
Note that each enter method activates everything that is important for
its particular state, and--this is the important part--the
corresponding exit method turns off or undoes everything that
was turned on by the enter method. This means that whenever the FSM
leaves a particular state, you can be confident that it will
completely disable anything it started when it entered that state.
Now to switch from Walk state to Swim state, you would just need to
request a transition, like this:
This FSM is a very simple example. Soon you will find the need for
more than two states. For instance, you might want to play a
transition animation while the avatar is moving from Walk state to
Swim state and back again, and these can be encoded as separate
states. There might be a "drowning" animation if the avatar stays too
long underwater, which again might be another state. Graphically,
this now looks like this:
↗ |
Walk2Swim
|
↘ | | |
Walk
|
|
Swim
| |
→ |
Drowning
|
↖ |
Swim2Walk
|
↙ | | |
In a real-world example, you might easily find you have a need for
dozens of states. This is when using the FSM class to manage all of
these transitions for you can really make things a lot simpler; if you
had to keep all of that cleanup code in your head, it can very quickly
get out of hand.
|