I've merged the FSM branch into master. The way finite state machines work is...
A finite state machine will alter the components that are an entity has based on the current state. By altering the components we alter the systems that process the entity and thus its behaviour.
You create a state machine with
var fsm : EntityStateMachine = new EntityStateMachine( entity );
You define the states with a fluid interface like this -
fsm.createState( "guard" )
.add( Patrol ).withInstance( new Patrol( guardPath ) );
fsm.createState( "investigate" )
.add( Investigate );
fsm.createState( "defend" )
.add( Defend );
You can add multiple components to a state
fsm.createState( "playing" )
.add( Motion ).withInstance( new Motion( 0, 0, 0, 15 ) )
.add( MotionControls ).withInstance( new MotionControls( Keyboard.LEFT, Keyboard.RIGHT, Keyboard.UP, 100, 3 ) )
.add( Gun ).withInstance( new Gun( 8, 0, 0.3, 2 ) )
.add( GunControls ).withInstance( new GunControls( Keyboard.SPACE ) )
.add( Collision ).withInstance( new Collision( 9 ) )
.add( Display ).withInstance( new Display( new SpaceshipView() ) );
var deathView : SpaceshipDeathView = new SpaceshipDeathView();
fsm.createState( "destroyed" )
.add( DeathThroes ).withInstance( new DeathThroes( 5 ) )
.add( Display ).withInstance( new Display( deathView ) )
.add( Animation ).withInstance( new Animation( deathView ) );
(that code is taken from the asteroids example project).
You change state with
fsm.changeState( "playing" );
Finally, you will usually want to add the state machine to a component so it can be used by the systems that need to change the state.
The state machine relies on component providers, which hide behind the fluent interface. There are three providers included -
The type provider provides a new instance of the given type whenever the state is entered
state.add( componentType : Class ).withType( instanceType : Class );
or
state.add( componentType : Class );
if componentType and instanceType are the same
The instance provider provides the given instance when the state is entered
state.add( componentType : Class ).withInstance( component : * );
The singleton provider provides the same instance whenever the state is entered, creating it when it is first required
state.add( componentType : Class ).withSingleton( instanceType : Class );
Finally, custom component providers may be used
state.add( componentType : Class ).withProvider( provider : ComponentProvider );
It is likely that more standard providers will emerge from use (e.g. a standard way to set the properties on a component), at which point they can be added to the library.
I hope all that makes sense. Have fun with it and let me know if it works for you. I have half-written a blog post about it which I may get finished next week.
Richard