10

Basically I have a state machine that controls a game character's attacks, with timings based on the animation length.

So for example:

I start at the default state, and if the player hits an attack button it starts an attack, switching the state and setting a timer based on the attacks length. The state machine gets more complex however when I consider charge attacks that can be cancelled, attacks that can move to different states depending on what they hit, and also every state has unique ways of dealing with the character being attacked. At the moment I have large switch statements. I thought about polymorphism but that would require a new class for every state for which there are a lot (starting attack, attacking and finishing attack all require separate states for example).

The switch statement works, but its quite large and also isn't as easily modified as an inheritance based system.

Any suggestions on good looking implementations?

EDIT: This is using java.

Cratylus
  • 52,998
  • 69
  • 209
  • 339
deek0146
  • 962
  • 6
  • 20

5 Answers5

9

With larger state machines you must watch out for the "transition explosion" phenomenon. It turns out that the traditional Finite State Machines don't provide mechanisms to reuse common transitions across many states, so you end up repeating too much and your state machine "explodes" (this goes also against the Do-not-Repeat-Yourself (DRY) principle).

For that reason I would recommend using hierarchical state machines and and implementation technique that allows easy mapping such state machines to code. For more information about hierarchical state machines, see the Wikipedia article http://en.wikipedia.org/wiki/UML_state_machine.

Miro Samek
  • 1,909
  • 14
  • 19
3

Consider building a table-driven state machine. If you think about the definition of a state machine, you have basically a set of states with a distinguished initial state, a transition function, and (in this case) an input and output alphabet.

You can construct a table indexed by current state and input, and use a pointer to function, or a functor class, to represent what happens. That function should return the next state. Then you can build the state machine as (pseudocode):

 state := initial state
 while(state != STOP)
    state := (lookupTransition(inputs))()

where lookupTransition(inputs) simply finds the next state. I'm assuming here that the transition functions are functions of no arguments returning state, so lookupTransition(inputs) has to be a function of however many inputs you have, returning a pointer to function of void arguments returning state.

Set this up correctly, and you can put all the state machine and behavior into one table, which can be easily modified and recompiled.

(For extra credit, figure out how you can load that table from a file, so you don't need to recompile at all.)

Update

In Java, use something like a functor class in place of function pointers.

Another Update

Of course, another option is to use a state machine compiler like Ragel.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • That's the real problem isn't it. As soon as you need a new class for each state/event combo, the code gets very verbose. We'll have to wait for closure to finally being able to do such things succinctly. For now, reflection or code generation can be used to reduce code clutter, with their own drawbacks. – irreputable Jun 16 '11 at 21:25
  • You know, honestly, I suspect there's a deree of essential complexity here. Having closures only helps by a line or two per transition; using functors makes that code sort of cookie-cutter, but the complexity isn't all that different. Using a dynamic language, like Ruby or Python or Groovy, might help a little, but primarily because it would make the table loading part easier. But eventually, if you have a complicated state machine, you're gonna have to write code. – Charlie Martin Jun 17 '11 at 02:16
1

By my side I am using stateforge an HFSM( http://www.stateforge.com/ ). Parallel state ,Hierarchical approach and the observer can solve quite a lot of complex case.

Thiem Nguyen
  • 6,345
  • 7
  • 30
  • 50
popolsky
  • 11
  • 1
1

Boost has a perfectly fine state machine, the only drawback is getting used to template / type programming

http://www.boost.org/doc/libs/1_46_1/libs/statechart/doc/index.html

totowtwo
  • 2,101
  • 1
  • 14
  • 21
  • I am used to template programming, however I'm currently using java I probably should have mentioned that. – deek0146 Jun 16 '11 at 20:56
0

I can't say I've ever used it but there is http://commons.apache.org/scxml/. It's also not that hard to write by hand, using the table based approach suggested by others.

Kevin
  • 24,871
  • 19
  • 102
  • 158