Precision on StateMachines

Started by
6 comments, last by frob 9 years, 6 months ago

Hi everyone,

I'v a little issue on how I should implement a state machine logic in my game.

(as described in http://www.gamedev.net/page/resources/_/technical/game-programming/state-machines-in-games-r2982)

I'm programming a platformer and state machine logic seems fine for it except for one particular case.
Let say I've three states for the player, idle, walk and attack

  • idle is the beginning state.
  • walk is triggered when pressing a direction and end when this direction is released or when another state is called.
  • attack is triggered when attack button is pressed.

All of thes states are neighbors from each other : each of them can transition to one another.

But if I press a direction, then the attack button (without releasing direction), when attack state is expired, the character should transition back to walk.

There's a bunch of solution tha crosses my mind for that but I'm not sure what's the best :

  • character has an internal state walking or not triggered by direction down and direction up, which is used to choose the next state after attack. It seems a little clumsy as it is kind of a parallel state machine.
  • adding an input event "direction pressed" in addition of "direction down" and "directionup" which is fired in event queue from the moment direction is pressed until it is released, walk event should be now triggered by this event.

or other things I hevn't thought of.

What do you think ?

Advertisement

(as described in http://www.gamedev.net/page/resources/_/technical/game-programming/your-first-step-to-game-development-starts-here-r2976)

I'm not sure where in the cited article a state machine is described. So I assume you are speaking of explicitly modeling a state machine in code. Here are some thoughts:

1.) Parallel state machines and hierarchical state machines are invented after noticing that a single state machine is not suitable to handle more complex situations well. In this sense it is not really clumsy. However, I'd not categorize your current need as complex situation.

2.) If the amount of belonging states is low, in this case the amount of states denoting moving, then the "combinatorial explosion" (that originally led to hierarchical state machines) can be accepted. I.e. all the states { move_forward, move_backward, ..., attack_forward, attack_backward, ... } may be generated, so that attacking states have the following state implicitly implemented. This is a clean solution from the point of view of a standard state machine, but obviously not the most popular one w.r.t. developers ;)

3.) Activation and de-activtion of states can be explicit, i.e. there are State::enter and State::exit methods which are invoked on the next current and the now obsolete current states, resp. When the invocation passes the other state as argument, the next current state can store it for later use. This would implement a dynamic transition mechanism.

4.) A more general approach would be to have a state stack where the current state can look up a kind of history of state invocations. This also would allow for a dynamic transition mechanism.

5.) The state machine need not necessarily be explicit. In fact a computer works as a state machine anyway. The set of current values of every variable in your game can be understood as the current state, and changing the values can be understood as transition. For example, a variable action may have the value 0 for standing, 1 for moving, 2 for attacking. Another variable direction may have the values 0 to 3 for forward, left, right, backward, resp. The values of action and direction then make the state. As you can see, at any time they have one of 12 possible values.

Sorry, my bad, the link wasn't the intended one. I corrected it.

Thank you for you're answer, I'll look a deeper into it.

1,2)

I consider more and more having two state machine because the case I described is not really the only one after all. I realized that in 2). As my game is 2d, there is actually two direction to attack so instead of just having an attribute facing left or facing right, it could be another state machine... Then I realized there are more states than I thought (attack while in mid air, facing left, right etc...). Even if sprite and hitboxes will be the same inverted, that's different states !

The fist would be conditionned by my movement vector (walking_right walking_left, falling, ascending...)

The second by the input (attacking, jumping, countering etc...).


Another way to do things when I look at 3), is having more states with different default next state. In my case, a attack (idle neighbor) that leads to idle state and a walkattack (neighbor of walk) that leads to walk state, even if these two states are resulting in the same animation...

4) The stack thing is tempting but seems too generic for what I want to acheive. I'll think of it if I ever tried to do a versus fighting game !

5) I really want it to be explicit because I'm working in collaboration with another game designer, who's not a programmer at all.

States machines are more complex than I thought, but I still stick to it because I feel it might prevent complex bugs (which is worse !).

Sometimes you can use overlapping state machines. You might be able to mix "walk" and "chew gum" at the same time because they animate different parts. Trying to animate "attack" and "run" at the same time, probably not.

Often you will have large clusters on your animation state machines. You can have a "run" loop that also has little spurs for "run and swing left", "run and swing right", "run and strike down". Also a state machine is not a stack, you don't need to return through the same path. You could have a path "Run" -> "Forward high power downstrike stab" -> "kneeling" -> "Stand from kneeling" --> "idle".

It may have a few combinations, but not necessarily combinatorial explosion. Your controller may have 12 buttons, and combinatorial explosion would mean handling all 4096 options at every hub. Usually you only have three or four valid paths though a hub. While running you might be able to swing left, swing right, swing up, and stab forward and down, turn right, turn left, slow to walk, and stop short. You can't do all three swings simultaneously while running.

In nearly every game I've worked on, state machines tended to have clusters like that. Individual scripts are assumed to start and end in idle, so it is basically a giant hub. Yet you can have smaller hubs at any other portion of the state machine. You might have a sitting hub with lots of things you can do from a sitting idle loop. You might have a dancing hub with lots of dance steps you can do from a dancing idle loop. You might have a running hub where you have a bunch of things you can do from a running idle loop.
For my little hobby projects I've started taking cues from more complex 3D games and going for a full data-driven animation state machine that drives all game character behavior. It actually simplifies your code quite a bit as it allows you to tie behaviors to events and state variables purely in data and decoupling all of the messy game logic from any hard-coded state machines.

The animation data gets more complex but everything else gets simpler. It's also much more easily data-driven. There're tools for building nice animations (2D or otherwise) using the approach.

For instance, characters have a few states: standing idle, walking, running, jumping, attacking, being hurt, etc. You can make copies for each direction or you can use state variables. All player input ends up being routed into the animation, the animation makes determinations as to whether a transition is legal (e.g. the hurt animation takes 0.5 seconds and has no transitions available until it's complete, effectively stunning the player after being hit... if you want to set it up that way). Likewise, the walking animation exports a "speed" or "impulse" variable that the character controller binds to the physics object, meaning that the animation can be in full or partial control of whether the player can actually move (and how fast). The player controller's job then is mostly just to route interesting events into the animation, feed it with state variables (is Left being pressed, etc.), and poll animation state variables to feed out to other systems. The animation can also trigger events during animation timelines or transitions for things like sound effects, particle effects, etc. so you can get accurately timed and synchronized footstep effects, timed attack hitboxes, and so on. Attachment points controlled per frame likewise let you do a lot of things.

The animation states can be easily specified in XML or JSON or whatever and edited with a number of different animation tools. Creating animations becomes more complex but far more powerful and flexible for the content creator and the total amount of code needed for new characters or AIs drops quite a bit.

That's all pretty much how we build skeletal animations and designer/artist-controlled character behavior in big 3D games. As much as possible it offloaded to the animation. A component might end up supplying some additional configuration data (e.g., speed scalars combined with animation movement outputs) but it does relatively little actual work.

The problem with hierarchical state machines for player control is that they don't match up with animations. Sure, yes, you can be walking left indpendently of whether you're attacking, but the resulting animation you play is very much dependent on both of those states. If you have completely independent hiarchical states then you still end up needing a full animation state system that can transition to the proper animation based on both controller state inputs. Or you can use a split player sprite (lower and upper torso) but the results of that make your game look pretty sub par.

Sean Middleditch – Game Systems Engineer – Join my team!


What do you think ?

i think you're tracking two states (moving and attacking) with one state variable.

as frob says, you can enumerate the combos as a single state variable, or use individual state variables, as described by sean:


If you have completely independent hiarchical states then you still end up needing a full animation state system that can transition to the proper animation based on both controller state inputs.

in a recent refactoring of AI code in my own project, i got good results switching from a single state variable to multiple state variables. and as sean says, you need an animation system that can draw whats required, whether that data is stored in a single state variable ,or multiple state variables, in my case, the possible combos of taking fire, recovering from collision, resting due to fatigue, following orders, hunting, grazing, sneaking, moving, attacking, etc made multiple state variables the only real way to deal with things

.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Thanks for thes enlightening answers. I know have a clearer vision of what I need to do :

2 state machines : action and movement (where attack is an action and walk a movement), and a bunch of activities corresponding to combination of states.

A can have object can have of course only one activity at a time.

  1. Player start moving : action = Idle, movement = walk >> walk activity
  2. player pushes the attack button without releasing direction : action = attack, movement = walk >> attack activity
  3. attack animation ends, action return to idle and movement still = walk >> walk activity


2 state machines : action and movement (where attack is an action and walk a movement), and a bunch of activities corresponding to combination of states.
A can have object can have of course only one activity at a time.
That may be an option for your code, but it is not an option frequently taken in bigger games. Usually locomotion (walking, running, sprinting, crawling, etc.) is considered an action or activity itself, and is not allowed to be mixed with other items.

If your game is built such that the two are truly independent, that is, an attack is entirely upper body and does not involve the legs at all, then it may work. That will probably not work in practice, because compelling attack animations involve the full body. Without it either the swings will look feeble or the body will appear horribly out of balance. I imagine their legs are daintily running while their arms are involved an a half-body body-slam, not slowing the legs nor using them for force or balance.

This topic is closed to new replies.

Advertisement