Quick and dirty Finite State Machine script

Hi community,
yesterday I had to put together a FSM for my game, at first I looked at what’s already out there but I found it to be quite heavy to pick and adapt, so I decided to code another one that is faster to use once you inserted the script in your library.

here is how you use it:
1)define an enum with all the states
2)for each state declare a StateContent using as a parameter a delegate function that returns the next state where you want to transition to from the one you are declaring
3) put each enum value in couple with his StateContent in a Dictionary
4) declare the FiniteStateMachine
5) have fun.

each StateContent allows you to set 3 other functions to be called:
-onLeavingState
-onStateReached
-behaviour

The onLeavingState is automatically called once when the state is left (before the transition or actually as first thing when the transition happens).
The onStateReached is automatically called once when the state is reached (at the end of the transition function)
To call the behaviour you use the makeBehaviour function of the FSM, while to call a transition you use the makeTransition function.

Each one of these functions will return an object and take an object as a parameter, but the return values of the onLeavingState and onStateReached are inaccessible right now (but I’m thinking of having the maketransition return them in an array or a list), while the one of the behaviour function is returned from the makeBehaviour.

Here is an example (my test code, actually):

enum states {start,middle, altmiddle, final};

                StateContent startingState=new StateContent(delegate(object par) {
		Debug.Log("#state init TransitionCondition");	
		if((bool)par)
		return states.middle;
		else
		return states.altmiddle;
			});
			startingState.Behaviour= delegate(object par) {
				Debug.Log("#state init ###behaviour");	
				return null;
			};
			
			startingState.OnStateReached= delegate(object par) {
				Debug.Log("#state init ###OnStateReached "+par);	
				return null;
			};
			
			StateContent middleState=new StateContent(delegate(object par) {
				Debug.Log("#state middle TransitionCondition");	
				return states.final;
			});
			
			
			StateContent altState=new StateContent(delegate(object par) {
				Debug.Log("#state alt TransitionCondition");
				return states.final;	
			});
			StateContent finalState=new StateContent(delegate(object par) {
				Debug.Log("#state final TransitionCondition");	
				return states.start;
			});
			Dictionary<System.Enum,StateContent> graph= new Dictionary<System.Enum, StateContent>();
			graph.AddOrUpdate(states.start,startingState);
			graph.AddOrUpdate(states.middle,middleState);
			graph.AddOrUpdate(states.altmiddle,altState);
			graph.AddOrUpdate(states.final,finalState);
	
			FiniteStateMachine fsm= new FiniteStateMachine(graph,states.start);
			fsm.transitionFunct=delegate(object par){ Debug.Log("exampletransition 1"); return null;};
			fsm.makeBehaviour(null);
			fsm.makeTransition(true,null,null,null);
			fsm.makeBehaviour(null);
			fsm.makeTransition(true,null,null,null);
			fsm.makeBehaviour(null);
			fsm.makeTransition(false,null,null,null);
			fsm.transitionFunct=delegate(object par){ Debug.Log("exampletransition 2"); return null;};
			fsm.makeBehaviour(null);
			fsm.makeTransition(false,null,null,null);
			fsm.makeBehaviour(null);
			fsm.makeTransition(false,null,null,null);

Here is the thing:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public delegate object stateBehaviour(object par);
public delegate object transitionBehaviour(object par);
public delegate System.Enum transitionCondition(object par);

//classe/struttura dati che contiene tutte le funzioni da associare ad uno stato
public class StateContent
{	
	//funzione che gestisce la transizione da questo stato al successivo
	transitionCondition transition;
	public transitionCondition Transition {
		get {
			return this.transition;
		}
	}
	
	//funzione che viene eseguita all'entrata nello stato (dopo la transizione)
	bool onStateReachedSet=false;
	stateBehaviour onStateReached;
	public stateBehaviour OnStateReached {
		get {
			if(onStateReachedSet)
				return this.onStateReached;
			else
			return delegate(object Par) { return null;};
		}
		set {
			onStateReached = value;
			onStateReachedSet=value!=null;
		}
	}
	
	//funzione che viene eseguita all'uscita dallo stato (prima della transizione)
	bool onLeavingStateSet=false;
	stateBehaviour onLeavingState;
	public stateBehaviour OnLeavingState {
		get {
			if(onLeavingStateSet)
				return this.onLeavingState;
			else
			return delegate(object Par) {return null;};
		}
		set {
			onLeavingState = value;
			onLeavingStateSet=value!=null;
		}
	}
	
	//comportamento assegnato a allo stato
	bool behaviourSet=false;
	stateBehaviour behaviour;
	public stateBehaviour Behaviour {
		get {
			if(behaviourSet)
				return this.behaviour;
			else
			return delegate(object Par) {return null;};
		}
		set {
			behaviour = value;
			behaviourSet=value!=null;
		}
	}	
	
	//costruttore, richiede solo la transition, gli altri vanno assegnati con le property.
	public StateContent (transitionCondition transition)
	{
		this.transition = transition;		
	}
	
	

}

public class FiniteStateMachine {
	public System.Enum current;
	public Dictionary<System.Enum,StateContent> stateSet;
	
	//permette di impostare una funzione da eseguire *ad ogni transizione* la stessa per tutti gli stati.
	//NB la stateContent.transition di quello stato viene eseguita *prima* della onLeavingState
	bool ontransitionFunctSet=false;
	transitionBehaviour ontransitionFunct;
	public transitionBehaviour OntransitionFunct {
		get {
			if(ontransitionFunctSet)
				return this.ontransitionFunct;
			else
			return delegate(object Par) {return null;};
		}
		set {
			ontransitionFunct = value;
			ontransitionFunctSet=value!=null;
		}
	}
	
	//costruttore, richiede un dictionary di associazioni valore-enum/statecontent e lo stato iniziale.
	//per definire le transizioni si usa il valore di ritorno delle transition messe nel costruttore degli stateContent
	public FiniteStateMachine (Dictionary<System.Enum,StateContent> stateSet, System.Enum startingState)
	{
		this.stateSet = stateSet;
		
		if(stateSet.Count>0)
			current=startingState;
	}
		
	/// <summary>
	/// esegue la transizione di stato fornendo gli input delle funzioni coinvolte
	/// </summary>
	/// <param name="transitionInput"> input di statecontent(di partenza).Transition.</param>
	/// <param name="onLeavingStatePar">input di statecontent(di partenza).OnLeavingState</param>
	/// <param name="onEnteringStatePar">input di statecontent(di arrivo).OnStateReached</param>
	/// <param name="onTransitionPar">input della funzione OnTransition della FSM.</param>
	public void makeTransition(object transitionInput, object onLeavingStatePar, object onEnteringStatePar, object onTransitionPar)
	{
	System.Enum next;
		next=stateSet[current].Transition(transitionInput);
		if(current!=next)
		{
			stateSet[current].OnLeavingState(onLeavingStatePar);
			OntransitionFunct(onTransitionPar);
			stateSet[next].OnStateReached(onEnteringStatePar);
			current=next;
		}
	}
	
	//esegue il behaviour dello stato corrente
	public object makeBehaviour( object behaviourPar)
	{
		return stateSet[current].Behaviour(behaviourPar);
	}
	
	//indica quale sarebbe il prossimo stato facendo una transizione con l'input in argomento
	public System.Enum getNextState(object transitionInput){
	System.Enum result;
	//DebugConsole.Log(" fin qui tutto bene "+current);
		result=stateSet[current].Transition(transitionInput);
		
	//	DebugConsole.Log(" fin qui mah: "+result);
		return result;
	}
}

Hope you enjoy it!

Added onTransition function!
Simple delegate function, the same for all states but is public so it can be edited before the transition if needed.