Finite State Machine

As I am diving deep into coding the AI behaviors of my game, I realized that I am incorporating complex and confusing boolean operations in order to “change the state.” I’ve figured its time to incorporate a FSM to allow an easy workflow of creating new actions and states. I’ve looked at some threads where people say they are working on classes but the threads seemed to die down. I’m looking for a relatively basic framework where I the AI can investigate, wander, cover, and a few other things. If anyone could point me into a direction on the forums or if anyone knows any links to help out that would be awesome!

1 Like

This is a useful resource on FSMs. The stack-based FSM is particularly attractive.

1 Like

Hi,

FSM has a very wide range of usecases in game programming.
Make a FSM to use is a few line of code for skilled Java dev.

As my experience, if you just write a small game you should write the FSM your self and make it efficient and optimized for your case. Generic (that’s also mean use <Class> in your java source code, come with perfomance cost when interfering the class)

None generic and full fledge implementation http://sourceforge.net/apps/mediawiki/tungsten/index.php?title=Introduction_to_Tungsten_Finite_State_Machine_Library

A generic and fulent fsm with builder but non scriptable http://code.google.com/p/stateless4j/ . It’s a good implementation i recommended to use

More generic usecase lead to an FSM with Guard, with Conccurent and may be Hierchical or Scriptable. try http://chsm.sourceforge.net/

So for your AI, you can use one of 3 above (beside of other)…

Ex: Stateless4j
Just wrap your activity into update method of the state. Config the transistion and the input intepreter.

aiFSM.Configure(Walk)
.OnEntry(startAnimWalk)
.OnExit(stopAnimWalk)
.Permit(Run, SpeedUpEvent)

class Walk{
public void update(tpf);
}


class Agent{
public void update(tpf){
fsm.getCurrentState().update(tpf);
}
}

Hope this help,

1 Like
@atomix said: Hi,

FSM has a very wide range of usecases in game programming.
Make a FSM to use is a few line of code for skilled Java dev.

As my experience, if you just write a small game you should write the FSM your self and make it efficient and optimized for your case. Generic (that’s also mean use <Class> in your java source code, come with perfomance cost when interfering the class)

None generic and full fledge implementation http://sourceforge.net/apps/mediawiki/tungsten/index.php?title=Introduction_to_Tungsten_Finite_State_Machine_Library

A generic and fulent fsm with builder but non scriptable Google Code Archive - Long-term storage for Google Code Project Hosting. . It’s a good implementation i recommended to use

More generic usecase lead to an FSM with Guard, with Conccurent and may be Hierchical or Scriptable. try http://chsm.sourceforge.net/

So for your AI, you can use one of 3 above (beside of other)…

Ex: Stateless4j
Just wrap your activity into update method of the state. Config the transistion and the input intepreter.

aiFSM.Configure(Walk)
.OnEntry(startAnimWalk)
.OnExit(stopAnimWalk)
.Permit(Run, SpeedUpEvent)

class Walk{
public void update(tpf);
}


class Agent{
public void update(tpf){
fsm.getCurrentState().update(tpf);
}
}

Hope this help,

Do these support the ability to interupt the current state based on certain events?

interupt can mean two different thing:

  • normal interupt in an FSM is to “change” from one state to another state via transistion with some meaningful event and it’s an normal operation. A state can also made its fsm shutdown by calling terminate on the fsm.

  • if you mean interupt “a thead” in paralel enviroment is totally different, so the state bounded to the thead will also be interupt and invalid lead the fsm to retry to shutdown…, only chfm support that feature.

So in the case your update in the AIState is a long task. You should have another thread to run the heavy task and watch it from the current thread. When meaningful event come and tell your fsm to change state; your original thread tell the heavy thead that it will be interupted; General speaking, stop() is not good for conccurent and also AI (as my experience in the field), you should can interupt() and let the heavy thread decrease its operation to none and then return.

Note that’s a very simple trick of conccurent and multi-thread.

[Read only if you interesting in writing a AI fw] In my AI framework, called AtomAI. From overview, a sotiphicated load balance executor manage thread and workload in more abstract unit: tasks and workers (some worker in one thread). Worker can have state and when a state is invalid, it try to dim the state execution to none. This can happen because they use a kind of “incremental” data, when the incremental unchange, the execution of the state find no interesting more in the data and slow down its execution to even stop and return. That’s a kind of magic for java programming but in fact is not. It’s just a strict contract of how to implement a incremental and progresive AI agent for the good of all. So you may have some ideas about the problem.

@Sploreg said: This is a useful resource on FSMs. The stack-based FSM is particularly attractive.
Thank you for that! It does seem simple and the tutorial is great. As I am trying to implement the Stack-FSM class, he uses "functions" to store the state I believe. I don't know if that is a specific class to his engine or if there's a similar way to do that in java.

His functions are like Groovy Closures, or lambda expressions. You can use lambda expressions in Java 8.
Or just make an interface with an update() method and stack instances of that interface.

Thanks for this link, i did a little piece of code, check it out and tell me if you have any remarks.

State Class :

package util.stateMachine;

/**
 *
 * @author 
 */
public abstract class State {

    /**
     * Name of this State.
     */
    private final String name;
    
    /**
     * The current StateMachine. 
     * Allow you to change the current StateMachine State. 
     * Allow you to stacke an other Sate while you are in this one.
     */
    private FinitStateMachine csm;

    public State() {
        //Generate a name from de class name
        //thanks to inner class overide, that will give us a custome name.
        this.name = this.getClass().toString();
    }

    public State(String name) {
        this.name = name;
    }

    /**
     * Called by the StateMachine when update this Sate
     * @param tpf time between two updates
     */
    protected abstract void update(float tpf);

    /**
     * Called by the StateMachine when enter this State.
     */
    protected void enter() {
    }

    /**
     * Called by the StateMachine when leave this State.
     */
    protected void leave() {
    }

    /**
     * Usefull to print this current State of the StateMachine
     * @return (name + " (State)")
     */
    @Override
    public String toString() {
        return (name + " (State)");
    }

    /**
     * Called by the StateMachine on enter.
     * @param fsm current StateMachine
     */
    protected final void enter(FinitStateMachine fsm) {
        setCurrentStateMachine(fsm);
        enter();
    }

    /**
     * Set the currentStateMachine csm value to fsm.
     * @param fsm the new current FinitStateMachine.
     */
    private void setCurrentStateMachine(FinitStateMachine fsm) {
        this.csm = fsm;
    }

    /**
     * Get the currentStateMachine.
     * @return csm the currentStateMachine
     */
    public final FinitStateMachine getCurrentStateMachine() {
        return this.csm;
    }
    
    /**
     * Provide a "null" value for a State and allow to still do the update.
     * This way, the StateMachine don't have to check if the currente state is a null object.
     */
    public static final State NULL_STATE = new State("NULL_STATE") {
        @Override
        public void update(float tpf) {
        }       
    };
}

FinitStateMachine class :

package util.stateMachine;

/**
 *
 * @author 
 */
public class FinitStateMachine {

    /**
     * Store the current State of this StateMachine.
     * By default the value is set to NULL_STATE
     */
    private State currentState = State.NULL_STATE;

    /**
     * Updating this StateMachine will update the current State.
     * @param tpf time between two updates
     */
    public void update(float tpf) {
        currentState.update(tpf);
    }

    /**
     * Change the current state to the new state. 
     * You can't set the same State.
     * leave the old State and enter the new one.
     * @param state the new state
     */
    public void setState(State state) {
        if (!currentState.equals(state)) {
            this.currentState.leave();
            this.currentState = state;
            this.currentState.enter(this);
        }
    }

    /**
     * To get the current State of this StateMachine
     * @return the current State
     */
    public State getCurrentState() {
        return this.currentState;
    }
   
}

StackStateMachine class :

package util.stateMachine;

import java.util.Stack;

/**
 *
 * @author 
 */
public class StackStateMachine extends FinitStateMachine {

    /**
     * The stack of States.
     */
    private Stack<State> stackedStates = new Stack<>();
    
    /**
     * The previous state, used only for detecting state changes 
     * and still be able to leave the old state before changing.
     */
    private State previousState = State.NULL_STATE;

    /**
     * Pop the current State in the stack.
     * If the stack is empty or it was the last State return NULL_STATE,
     * else return the new State.
     * @return the new current State if no States remains return NULL_STATE
     */
    public State popCurrentState() {
        if (stackedStates.isEmpty()) {
            return State.NULL_STATE;
        } else {
            stackedStates.pop();
            return getCurrentState();
        }
    }

    /**
     * Push the new State into the Stack.
     * You can't push the same State as the currente one.
     * @param state the pushed State
     */
    public void pushState(State state) {
        if (!getCurrentState().equals(state)) {
            stackedStates.push(state);
        }
    }

    @Override
    public void update(float tpf) {
        checkForStateChange();
        getCurrentState().update(tpf);
    }

    @Override
    @Deprecated
    public void setState(State state) {
        popCurrentState();
        pushState(state);
    }

    @Override
    public State getCurrentState() {
        if (stackedStates.isEmpty()) {
            return State.NULL_STATE;
        } else {
            return stackedStates.lastElement();
        }
    }

    @Override
    public String toString() {
        return ( "StackFinitStateMachine (" + stackedStates.size() + ") : " + stackedStates.toString());
    }
    
    /**
     * Used to check any State change between two updates of the StateMachine.
     * This way allow you to stack multiples State but doing only one State change
     * (ie leaving the old one and enter the top stacked one)
     */
    private void checkForStateChange() {
        if (!previousState.equals(getCurrentState())) {
            previousState.leave();
            getCurrentState().enter(this);
        }
        previousState = getCurrentState();
    }
    
}

Hi

I advise you to use the Fettle API, it’s really well designed, not bloated. It’s an open source state machine framework. It’s used by King (Candy Crush, …) and me.

Thanks, looks good.