Ah so you are back for round #2? The first part of this tutorial was actually pretty straightforward stuff - in this section we are going to start to build our FSM framework so that we can write performant, neat code.
It's a bit like you decided to by a new laptop and the salesman says, "Great let me explain the silicon etching process used to build the processor! Don't worry it only takes about an hour."
Video
Tutorial Project
You can download the tutorial project from here.
Motivation
Our motivation for this part of the tutorial is to create something really powerful, a new way of writing code when you are implementing states that keeps everything clean.
- Let states dictate their startup and exit conditions
- Increase source code readability and reduce code indentation by having the individual routines broken out
- Keep all of the code for a state together in the source file
State Setup & Tear Down
First lets think a bit more about states. If we look at the code in our switch based example from #1 we will see that actually we hadn't completely managed to get all of the logic for our attack and hit states into one place. The configuration, the setup, for the states had to be done inline where we set the currentState variable. That's pretty obvious in the setting of the attack state:
if( distanceSquared < _maximumAttackEffectRangeSquared && _angleToTarget < 60f)
{
//Set the current state
currentState = EnemyStates.attacking;
//Setup the animation
_attack.enabled = true;
_attack.time = 0;
_attack.wrapMode = WrapMode.ClampForever;
_attack.weight = 1;
//Set a variable to make sure we know we
//haven't inflicted damage yet
hasStruckTarget = false;
return;
}
The attack state needs to wait for an animation, but the only place to configure that animation is when we set the state - the animation has to be running when we get into the Update function for the state. But really we shouldn't need to know about this stuff when we are effectively the client of the state - this code would need to be repeated in every place we started an attack. Definitely not DRY.
In fact the routines in a state might look like this:
This diagram does not imply order of function calls. Please note that OnGUI may well be called multiple times per frame. FixedUpdate may be called more than once in a frame, or not at all, based on how fast the game is performing compared to the Physics fixedStep.
So with this model a state is responsible for setting up its requirements when it is entered and tearing them down again when the state is exited. The promise here is that Exit State code will execute no matter how or where we leave the state. It's an important promise that will make our code much easier to write.
In fact some states are so simple that they could just do things in the Enter State, especially if that enter function was a coroutine that could execute over a few frames. Using the model we are going to build in this part of the tutorial an attack state is just this:
#region Attacking
IEnumerator Attacking_EnterState()
{
//Setup the animation for attacking
_attack.enabled = true;
_attack.time = 0;
_attack.weight = 1;
//Wait for half way through the animation
yield return StartCoroutine(WaitForAnimation(_attack, 0.5f));
//Check if still in range
if(target && (target.position - transform.position).sqrMagnitude < _maximumAttackEffectRangeSquared)
{
//Apply the damage
target.SendMessage("TakeDamage", 1 + Random.value * 5, SendMessageOptions.DontRequireReceiver);
}
//Wait for the end of the animation
yield return StartCoroutine(WaitForAnimation(_attack, 1f));
//Turn off the animation's effects
_attack.weight = 0;
//Decide on the next state based on whether
//intended victim is alive or not
currentState = target ? EnemyStates.Following : EnemyStates.Sleeping;
}
#endregion
One simple piece of code provides the setup and then the execution of the animation and damage provision. We're back to something that is easy to comprehend in one page of the editor.
It's All Done With Smoke & Mirrors
Ok it's time to lift the curtain and look at how we are actually going to build this FSM framework. Here's the first big clue - delegates.
It's time for some inheritance for our enemy controlling FSM - we are going to build a class called StateMachineBase that will actually be the underlying code that manages our states.
What we are going to do is have this new base class implement Update, OnTriggerEnter etc and have that implementation defer processing to a delegate, we will switch the delegates every time the state of the FSM changes.
What that means is that when, for example, Update is called on StateMachineBase it will delegate its processing to a delegate that represents the necessary functionality for the current state. That delegate will be a routine in our derived class (our enemy) or it will be a default routine that does nothing.
public Action DoUpdate = DoNothing; public Action DoLateUpdate = DoNothing; public Action DoFixedUpdate = DoNothing; public Action<Collider> DoOnTriggerEnter = DoNothingCollider; public Action<Collider> DoOnTriggerStay = DoNothingCollider; public Action<Collider> DoOnTriggerExit = DoNothingCollider; public Action<Collision> DoOnCollisionEnter = DoNothingCollision; public Action<Collision> DoOnCollisionStay = DoNothingCollision; public Action<Collision> DoOnCollisionExit = DoNothingCollision; public Action DoOnMouseEnter = DoNothing; public Action DoOnMouseUp = DoNothing; public Action DoOnMouseDown = DoNothing; public Action DoOnMouseOver = DoNothing; public Action DoOnMouseExit = DoNothing; public Action DoOnMouseDrag = DoNothing; public Action DoOnGUI = DoNothing; public Func<IEnumerator> ExitState = DoNothingCoroutine;
There they are - the delegates for our state machine. And here is the code that StateMachineBase uses to implement its Update method.
void Update ()
{
DoUpdate();
}
You may be used to writing event handlers in C# or another .NET language - those event handlers are implemented as delegates.
Here's a quick overview of why delegates are a good idea:
- Delegates are very fast - they are pretty much the same speed as calling a function
- By removing our switch statement we are no longer having to make a comparison for every possible state, so our code will run at the same speed no matter how many states we have
- Delegates let us write code that uses reflection to find the routines for our states by the convention of calling them STATE_FUNCTION
Delegates
Ok so lets work through these delegates then. .NET comes with two built in generic delegate types and you can also define your own, lets examine that method first. For example here we define a delegate for a method that has no return value and takes a parameter of type Collider (like all of the OnTriggerXXX functions):
public delegate void UnityTriggerFunctionDelegate(Collider collider);
We could then define a variable that could point to a trigger function like this:
UnityTriggerFunctionDelegate _triggerFunc;
And we could assign it to a method in our class like this:
void Start()
{
_triggerFunc = OnTriggerEnter;
}
void OnTriggerEnter(Collider collider)
{
//Do something
}
You would then call it like this:
_triggerFunc(someColliderYouFound);
Which is equivalent to calling OnTriggerEnter(someColliderYouFound), but if you later switched _triggerFunc to point to OnTriggerExit then the _triggerFunc(someColliderYouFound) call would then be the same as OnTriggerExit(someColliderYouFound).
Rather than typing all of that delegate definition stuff each time you want to make one (which can be very confusing anyway as you can have multiple delegates that refer to the same method signature) .NET defines two generic delegate types: Action and Func.
So using these generic classes we can rewrite our variable definition for _triggerFunc and do away with the UnityTriggerFunctionDelegate definition all together.
Action<Collider> _triggerFunc;
The Action class defines a delegate to a method that returns void and the generic arguments are the parameters to the function. So a delegate for a method that returned void and took a string and an int would look like this:
Action<string, int> variable;
The second type of built in generic delegate is Func the big difference being that the last generic argument is the return type of the function. So a method that returns an int and takes a string would look like this:
Func<string, int> variable;
Reflection
Right then - if delegates are our "smoke" then reflection must provide the "mirrors" for our implementation - dada dum tish (I'm here all week folks...)
Reflection is the much maligned and misunderstood method of reading the metadata of classes when your code is running. Metadata you ask? What I mean is that it gives you the ability to find all of the fields, properties, methods, parameters, return values of everything - even the private stuff. More than that, not only can you find these items, you can also dynamically call them and change values.
Reflection often has a bit of a bad name - for one thing, it lets you break encapsulation; using reflection you can access all of the supposedly hidden and private members of a class! At least you can if you have the security permissions and with Unity, you do have those permissions... It's also a bit slow: slow to find things and then very slow to dynamically invoke them.
Used correctly reflection is a massive asset and in this section we're going to see how we can use reflection to create super fast delegates to the methods used to implement our FSM.
Our First Reflection
Ok so how do we do this reflection stuff then - well that's what .GetType() is all about on every single object in .NET - it lets you find the Type and the Type lets us find the methods, etc etc
void CallMethod(object target, string name)
{
var mtd = target.GetType().GetMethod(name);
if(mtd != null)
{
mtd.Invoke(target, null);
}
}
Right, so what this does is it takes any object you pass to it, gets its Type and asks it to get a public method with the name passed in to our function - it does this by calling GetMethod. That method is returned as a MethodInfo class which provides lots of information about the actual code. If there was a public method called name then mtd will not be null, the example then it calls this discovered method with no parameters by using Invoke and passing the object instance and null as the second parameter (indicating that there are no parameters).
You might use our example function like this:
CallMethod(yourScript, "SomeMethod");
By default GetMethod only lets you retrieve public instance methods, but you could find private methods and static methods using GetMethod too - there's a version which takes a BindingFlags parameter that lets you specify lots of options.
Getting fields by name is a matter of calling GetField and it won't take a rocket scientist to work out that the equivalent for properties is GetProperty.
The purpose of this tutorial is not to teach you everything about reflection though - just enough for us to achieve our goal of a fast, convention driven FSM framework. For that all we need to do is access methods on a class.
Turning a Reflected Method Into a Delegate
Ok - so you've probably worked this out already but lets just summarise:
- Delegates are really fast, but we need some way to discover the methods rather than manually assigning them
- Reflection is really slow, but gives us a way to discover methods on our classes using a string
The Delegate class provides us with a static method called CreateDelegate that we can use to turn our reflected information into exactly what we need - a high performance delegate.
Now before we rush off and do that I want to take a moment to talk about a these delegates were going to create - there's a subtle fact here that you may well have missed.
An Action is a method with no parameters that returns no value. Here's a class with two methods that could be assigned to Action.
public class ExampleClass
{
public string somethingToLog;
public void Log()
{
Debug.Log(somethingToLog);
}
public static void LogCurrentTime()
{
Debug.Log(Time.time.ToString());
}
}
Yes both of those methods are suitable for Action, but one of them has access to the variables of the instance of the class and the other one doesn't. How does the Action value know that? The answer is a big topic in its own right; the answer is closures.
So behind the scenes when you write someObject.SomeMethod() - the compiler is effectively doing this SomeObjectsClass.SomeMethod(someObject).
Basically what needs to happen is that the instance of the class is bound to the delegate we create in the case of the instance method, and not in the case of the static method. After creating the delegate neither we nor the compiler will ever know whether this is a bound delegate or not, up until the point the code actually executes.
So we can write this code:
Action someAction = instanceOfExampleClass.Log;
When we use that example code then the instanceOfExampleClass is tied into the delegate created for the Log method before it is stored in someAction; and from then on calling someAction() will always call the Log method on that particular instance. It's hidden the reference to instanceOfExampleClass inside the delegate.
Of course we could write someAction = someOtherClassEntirely.SomeMethod() now calling someAction() calls that other class's instance method. If we set it to the static method then we wouldn't need the instance reference at all, yet it would still work!
When we assign a delegate like the previous example we are always creating a closed delegate - we say it has been closed over the instance or (in the case of the static) just the type reference.
Let's take a minute to look at some other example of closures, because at the moment you are right on the brink of understanding the most powerful feature of delegates and while we only need to understand closed delegates for our FSM framework it would seem wrong to leave you teetering on edge of this knowledge.
Closures
So you've seen how we can hide an instance reference inside a delegate to create a closure that means later on when we use the delegate we have no need to understand whether this Action is pointing to an instance member or a static member, or any need to know on what class this method exists. All we need to know is that we can call someAction() and it will just work.
Here's the big news: you can hide other variables inside a closure too!
To do that you are going to use anonymous functions; in other words, a function that isn't actually a part of your class, and doesn't have a name, but can act just as if it were. It's a function you define with code, or at least you define a bunch of its internal values and parameters with code.
We know that Action defines a function that returns nothing and takes no parameters. We know we can always call an action like this: someAction().
Let's create a little script that moves an object as a coroutine:
public static IEnumerator MoveThisObject(Transform objectToMove, Vector3 position, float period, Action onComplete)
{
//We are going to use t to represent the amount to lerp
//each frame
var t = 0f;
//Record the current position of the object
var startingPosition = objectToMove.position;
//Loop while we aren't at the end
while(t < 1)
{
//Lerp the object towards the target
objectToMove.position = Vector3.Lerp(startingPosition, position, t);
//Period is the time in seconds so we
//divide Time.deltaTime by it to get the
//amount to move this frame
t += Time.deltaTime / period;
//Yield until the next frame
yield return null;
}
if(onComplete != null)
onComplete();
}
So we have to start that script as a coroutine - The cool thing is the onComplete parameter - that's some function that will be called when the movement has finished.
Let's look at the easiest way of calling that function:
//We will use this inventory list in a while, it's basically
//a list of things you've picked up
List<SomeInventoryItemClass> myInventory = new List<SomeInventoryItemClass>();
void OnTriggerEnter(Collider other)
{
if(other.tag == "Pickup")
{
//Move an object to our current position
//over the period of 2 seconds
StartCoroutine(MoveThisObject(other.transform, transform.position, 2, Finished));
}
}
void Finished()
{
Debug.Log("Got here");
}
Ok so that moves the pickup to our location over 2 seconds - but if we wanted to then destroy the pickup game object and add it to our inventory then that would be kind of difficult. At the moment we have a lovely little function called MoveThisObject which would move anything anywhere - but how could we write Finished to actually destroy the object and add it to our inventory?
Are you thinking of setting some variables in the class that Finished would use? That won't work, what happens if you pickup two things before the first one has finished? You're stuck if you follow that approach.
So you might think the only way to actually do this is to write a new function that's called something like MoveThisObjectDestroyItAndAddItToMyInventory - hmmmm, a little less efficient if you have to write one of those for each of your functions. Not very efficient and decidedly not DRY.
This is an ideal use for an anonymous function and a closure. We are going to be able to keep MoveThisObject exactly as it is, yet be able to perform all of the actions we wanted.
Before we write our anonymous function let's just imagine what we would do if we just immediately picked up the object inside of the OnTriggerEnter and ignored our fancy movement coroutine.
void OnTriggerEnter(Collider other)
{
//Is the collider a pickup
if(other.tag == "Pickup")
{
//Get the script with the pickup information
var pickupData = other.GetComponent<PickupItem>();
//Add the item to our inventory
myInventory.Add(pickupData.item);
//Destroy the pickup object
Destroy(pickupData.gameObject);
}
}
Ok, its time for the best of both worlds - the best way to write an anonymous function in C# is to use lamba syntax - and I'm warning you, it looks kind of funky to start with. Persevere and it will become natural.
void OnTriggerEnter(Collider other)
{
//Is the collider a pickup
if(other.tag == "Pickup")
{
//Move the object, when finished add it to the
//inventory and delete it
StartCoroutine(MoveThisObject(other.transform, transform.position, 2,
()=> {
//Get the script with the pickup information
var pickupData = other.GetComponent<PickupItem>();
//Add the item to our inventory
myInventory.Add(pickupData.item);
//Destroy the pickup object
Destroy(pickupData.gameObject);
}));
}
}
Just look what we've hidden inside a simple Action that can be called with someAction(). We've closed it over the other collider that was passed in as a parameter to OnTriggerEnter and we've also closed it over this which is needed to access myInventory. If you entered a 1000 triggers at the same time, all of the objects would move to your position, be added to the inventory and be destroyed. I don't know about you, but I think that's pretty cool.
//Define a delegate that takes 2 ints and returns an int Func<int, int, int> someDelegate; //Later int result = someDelegate(4,4);
Now we could write these lambda functions:
//Lambda syntax with no code statements
someDelegate = (x,y) => x * y;
//The same thing as if it were a function
someDelegate = (x,y) => {
return x*y;
};
//A different one
someDelegate = (a,b) => {
var t = 0;
for(var i = 0; i < b; i++)
{
t += a - i;
}
return t;
};
//One that closes over something else!
void CreateAFunction(int someValue)
{
someDelegate = (a,b) => {
return a * b / someValue;
};
}
List<Action> resetPositions = new List<Action>();
void Start()
{
//Loop through all of the children of this
//game object
foreach(Transform child in transform)
{
//Take a copy of the iterator for closing
var closeChild = child;
//Get the position of the child
var position = child.position;
//Create a function to reset the position
//and add it to the list
resetPositions.Add(()=>closeChild.position=position);
}
}
void ResetAllChildPositions()
{
//Loop through our actions
foreach(Action a in resetPositions)
{
//Reset the position
a();
}
}
Meanwhile Back at the Ranch
Ok, back to the plot - we need to build an FSM framework. So to recap - we want to reflect to get methods and turn them into closed delegates.
So let's do just that. We are going to write a generic method that can get a delegate from the name of the current state and name of the function that we want to execute.
We always store our states in an enumeration and all enumerations are derived from the system class Enum, so our StateMachineBase class defines a currentState variable of type Enum so that in the derived classes we can create any old enumeration we like and still be able to set it to currentState. Moreover currentState will be a property so that we can write functions that cause something to happen as a side effect of setting it. Like this:
private Enum _currentState;
public Enum currentState
{
get
{
return _currentState;
}
set
{
_currentState = value;
ConfigureCurrentState();
}
}
So whenever we set the currentState we are going to call ConfigureCurrentState() that's the thing that will setup our delegates.
Now you can always get the name of the value of an enumeration by doing, for example, currentState.ToString() - handy!
Here's ConfigureCurrentState(), note how we have some delegates that return coroutines for the Enter State and the Exit State functions. As you can probably tell most of the magic is inside our generic method called ConfigureDelegate. We're passing it the name of the function we want, and a default value which is a delegate that fits the signature and does absolutely nothing. If the configure delegate call doesn't find one in the matching state it will use the empty function instead.
void ConfigureCurrentState()
{
//If we have an exit state, then start it as a
//coroutine
if(ExitState != null)
{
StartCoroutine(ExitState());
}
//Now we need to configure all of the methods
DoUpdate = ConfigureDelegate<Action>("Update", DoNothing);
DoOnGUI = ConfigureDelegate<Action>("OnGUI", DoNothing);
DoLateUpdate = ConfigureDelegate<Action>("LateUpdate", DoNothing);
DoFixedUpdate = ConfigureDelegate<Action>("FixedUpdate", DoNothing);
DoOnMouseUp = ConfigureDelegate<Action>("OnMouseUp", DoNothing);
DoOnMouseDown = ConfigureDelegate<Action>("OnMouseDown", DoNothing);
DoOnMouseEnter = ConfigureDelegate<Action>("OnMouseEnter", DoNothing);
DoOnMouseExit = ConfigureDelegate<Action>("OnMouseExit", DoNothing);
DoOnMouseDrag = ConfigureDelegate<Action>("OnMouseDrag", DoNothing);
DoOnMouseOver = ConfigureDelegate<Action>("OnMouseOver", DoNothing);
DoOnTriggerEnter = ConfigureDelegate<Action<Collider>>("OnTriggerEnter", DoNothingCollider);
DoOnTriggerExit = ConfigureDelegate<Action<Collider>>("OnTriggerExir", DoNothingCollider);
DoOnTriggerStay = ConfigureDelegate<Action<Collider>>("OnTriggerEnter", DoNothingCollider);
DoOnCollisionEnter = ConfigureDelegate<Action<Collision>>("OnCollisionEnter", DoNothingCollision);
DoOnCollisionExit = ConfigureDelegate<Action<Collision>>("OnCollisionExit", DoNothingCollision);
DoOnCollisionStay = ConfigureDelegate<Action<Collision>>("OnCollisionStay", DoNothingCollision);
Func<IEnumerator> enterState = ConfigureDelegate<Func<IEnumerator>>("EnterState", DoNothingCoroutine);
ExitState = ConfigureDelegate<Func<IEnumerator>>("ExitState", DoNothingCoroutine);
//Optimisation, turn off GUI if we don't
//have an OnGUI method
EnableGUI();
//Start the current state
StartCoroutine(enterState());
}
Ok so as you can see we have set each of our delegates, let's see how ConfigureDelegate works:
//Define a generic method that returns a delegate
//Note the where clause - we need to ensure that the
//type passed in is a class and not a value type or our
//cast (As T) will not work
T ConfigureDelegate<T>(string methodRoot, T Default) where T : class
{
//Find a method called CURRENTSTATE_METHODROOT
//The method can be either public or private
var mtd = GetType().GetMethod(_currentState.ToString() + "_" + methodRoot, System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod);
//If we found a method
if(mtd != null)
{
//Create a delegate of the type that this
//generic instance needs and cast it
return Delegate.CreateDelegate(typeof(T), this, mtd) as T;
}
else
{
//If we didn't find a method return the default
return Default;
}
}
Conclusion
I'll leave it to you to look through the code in FiniteStateMachine2 or you can review it with me in the video below. There are a few other features of StateMachineBase like waiting for animations and caching of common variables like transform, but we'll leave those to next time where they really come into play when we start injecting states into remote objects!
I know this has been a technical and rather advanced part - please remember, it's going to get easier again when the state machine system is finished.
Video
You might want to watch the video again now. Actually you might want a stiff drink or whatever form of distraction that your culture deems acceptable


November 6, 2012 - 9:47 pm
Very good post!
I consider myself a newbie programmer. Your tutorials are very useful. Recently I’ve been digging into them and try fully understand them.
I would appreciate a lot if you could introduce something about multiplayer game development using Unity. Actually I know nothing about how to setup a server nor any php stuff. And also little knowledge about the network API in Unity.
November 7, 2012 - 9:58 am
This fsm implementation might be good for everyday simple state machines but it has at least three obvious drawbacks:
1. I have to subclass StateMachineBase for every state machine I need which might be not possible even in case of MonoBehaviours. And I usually have many FSMs outside of MonoBehaviours.
2. While processing events you still have to use a lot of switch case currentState code.
3. Passing a parameter to a state_enter is hard. For example when I have a book I want a state OpenedAtPage(int pageNum). With current implementation I will have to set a property nextPage before changing state to FlipToPage instead of more elegant state = FlipToPage(42) or alike.
November 7, 2012 - 10:16 am
This is going to be quite a long series – as I’m effectively teaching how to build a framework and then use it…
1. In my full implementation of this I have a base state machine class that does not inherit from MonoBehaviour, I have a StatefulBehaviour that delegates to it. This will be introduced at the end of the series.
2. The implementation in the project supports that by using a delegated SendMessage, that will be introduced in the next part of series. The final chapter where I introduce the complete framework uses the same principle for .NET events as it does for Update etc which makes them very easy to implement differently for each state.
3. You could handle that in a couple of ways – in my (very complicated!) game I tend to use a state change function that can have parameters – but the paradigm of setting a variable (property) is simpler and much more like the traditional state machine switch statement approach. At the end of the day its the trade off between having to configure a parameter and having a clearly defined and immediately visible set of states that are kept together. It would depend on how often you pass parameters to states whether you decided to implement currentState as a struct or class that contained perhaps a hash of parameters that would be turned into named parameters in the function call.
November 7, 2012 - 10:44 am
> I have a StatefulBehaviour that delegates to it.
So you have to subclass it anyway. If my Unity development framework uses let’s call it AdvancedMonoBehaviour : MonoBehaviour I can’t use your fsm implementation, right?
> by using a delegated SendMessage
So you would have to call some SendMessage method in every event listener? Probably with an EventArgs parameter which forwards this call to a CurrentState_MyMessage(EventArgs params) method?
> At the end of the day its the trade off between having to configure a parameter and having a clearly defined and immediately visible set of states that are kept together.
BookAtPage(int) is a clearly defined state. How else would you implement it?
In everyday life in most statemachines there is at least one state with a parameter.
November 7, 2012 - 10:19 am
Actually I should probably say that in my game I use the principle of Blackboarding – where states access a common *blackboard* that contains the parameters they need and are activated for a particular task based on their *vote* of how well they can achieve it.
November 7, 2012 - 10:49 am
Like a separate object which holds parameters not to clutter up the main class?
I actually had been thinking about fsms for a very long time. Made a couple of frameworks which let you set up a fsm to use. I used enums, strings, objects as states. I tried keeping state-related data in such an object and pass it around as a boxed state. And much more. But eventually came up to a simple coding convention which doesn’t bring a framework with it, which is fast and easy to use. But I still like reading how other people implement fsms. Getting cool ideas from such posts but still don’t see myself using most of them.
November 8, 2012 - 2:50 pm
Valentin, I’ve gone through several FSMs and have not yet found one that I’m completely happy with. I am curious on your simple coding convention. Would it be possible to get an example project using it? Or just some code snippets if it’s that simple? Thanks
November 8, 2012 - 3:16 pm
Added a quick gist with comments.
https://gist.github.com/4039400
This works for us.
November 7, 2012 - 11:12 am
Yeah I understand that – that’s actually why I wanted to write a tutorial on implementing a state machine framework – because the ideas behind it might be useful in lots of places, even if you don’t use the finished article…
It’s actually a push though, because part of this tutorial is really about getting people to think in states too. Hopefully it will be clearer when I’ve finished it
November 7, 2012 - 12:00 pm
Keep the good work! q:
I liked your other articles about shaders.
November 24, 2012 - 12:29 am
Inspired by this article, I also wrote a post on FSM, but based on the GOF implementation of the Pattern.
http://www.doorapps.com/2012/11/22/finite-state-machine-pattern-in-unity-simple-version/
It serves the same purpose but it does it,in my opinion, in a much simpler way, without delegates/closures/reflections. Just old fashion inheritance and polymorphism
Let me know what you think.
Keep up the good work!
November 24, 2012 - 12:41 am
Yeah I like it
I started off that way myself (in fact my real version of the FSM has that and the delegate/reflection/closure stuff is an implementation of my IState interface – I just wrote it straight for the article to teach about those methods).
The reasons why I pretty much never write an IState implementation now though is that you need to teach it a lot about the game object that it is a part of – that takes a bunch of initialisation code and you end up with a lot of “through” references to the variables on the attached script. So for me, I prefer not to have the clutter and dereference performance of the classes and that extra code – but it’s a totally valid approach and allows swapping in states easily.
So I like the closure/delegate/reflection approach because it does this:
November 29, 2012 - 12:12 am
I’m kind of shocked to see that when you transition from one state to another, say from A to B, that B_EnterState will be called before A_ExitState. My test can be seen here: http://pastebin.com/yLaS1zZB
November 29, 2012 - 7:25 am
Very good spot mick – I totally forgot the code to run the coroutine once before handing it over to the normal processing (which is why exit is called after enter) – it should of course be executed immediately as well and it wasn’t happening. Need to modify this code from InterruptableCoroutine in StateMachineBehaviourEx:
/// <summary> /// Run the specified coroutine with an optional stack /// </summary> /// <param name='enm'> /// The coroutine to run /// </param> /// <param name='stack'> /// The stack that should be used for this coroutine /// </param> public void Run(IEnumerator enm, Stack<IEnumerator> stack = null) { enumerator = enm; if(stack != null) { _stack = stack; } else { _stack.Clear(); } //NEW LINE enm.MoveNext(); }November 29, 2012 - 7:30 am
I am uploading a replacement with that line fixed in it – will post here when the upload is complete
November 29, 2012 - 4:22 pm
Fully uploaded now
January 10, 2013 - 10:10 pm
Thanks for these tutorials
This is my first time trying to understand delegates and abstract functions and I think you did a good job of it, but I have to say its the hardest topic I’ve encountered yet! Quite a lot to keep in your head all at the same time.
I’m going through this line by line, and the first thing I don’t totally understand lies in very beginning of the abstract base class. What is the purpose of public new Transform, public new Rigidbody, etc?
I’m guessing its to cache these variables and I can see they are used in the inherited FSM classes, but why the new operation and using base.transform etc? What purpose is this serving?
January 11, 2013 - 6:59 pm
So I’m just really creating cached copies of the properties for the standard transform, rigidbody etc so that they are faster to access, given that most people like to use the original names this just ensures better performance by turning them from internal GetComponent calls to simple variables.
January 26, 2013 - 5:29 am
Just wanted to say thanks for the tutorial, I finally got my head wrapped around delegates and I have a working FSM based on your code!
January 27, 2013 - 3:11 am
Okay, I get the cached copy thing. I’ve got this up and working now, its awesome.
One thing though, what do you recommend doing in networked situations? In my case I’ve just got players (no NPCs) and I’m having a tough time thinking up a way to integrate this with Network.Instantiate because my prefabs all get controlled at the same time. It would ruin the elegance of this whole thing if I had to put if(isControllable) at the start of every function.,
January 31, 2013 - 8:25 am
Man, I really gotta say, this is the best state machine implementation ever. Thank you so much for putting this out there. It took me a while to learn the ins and outs but now I see that it is incredibly powerful!
February 20, 2013 - 7:14 am
I love this!
Pro Coding! Thank you so much! I am learning a lot! am really reallly happy :’)
May 6, 2013 - 9:04 am
Wow… for a beginner tutorial, it seems waaaaay convoluted!! Inheritance would seem so much simpler (a base State class, or an interface but with a class you don’t have to override everything), and as you said in another comment, what you’re effectively doing is reinventing the vf_table!
The only minor bonus I see here is I suppose a state can implement any callback either as a coroutine or a straight method… seems slim! Although with a class a normal method just has to wrap a coroutine inside a StartCoroutine(() => {…}); and voilà. Btw all those closures ain’t free you know!
I’m not saying your approach isn’t interesting, it’s just a) I fail to see the necessity, and b) boy I would never recommend a beginner to start with this!
One last thing I must point out that is just plain incorrect: the cost of a switch over an enum does NOT depend on the number of values in the enum! that’s what’s so great about switch, it’s basically free. See jump tables or branch table: http://en.wikipedia.org/wiki/Branch_table
So if your enum has 10 values, a switch costs as much as one branch (~ one if), not 10 branches.
May 6, 2013 - 9:22 am
Firstly this tutorial is not for beginners
The cost of a delegate is significantly less than the cost of bothering to do any part of a switch and makes the code far more legible in my book. I am aware that closures aren’t free and have impirically tested the performance.
Inheriting a class for each state makes reading parallel state machines very hard as its difficult to see which component is related to each other one. Multiple classes (not inheriting for MonoBehaviour requires lots of copied variables and static class references which I can live without!)
I find this to fit well with the normal model of coding Unity and produces highly legible modules which are easy to follow and debug. But we’ll, that’s just me!
May 6, 2013 - 9:41 am
Hey I’m not saying go with an enum/switch-based FSM, I’m just saying it doesn’t cost as much as the number of states (you mentioned “comparison with every possible state”).
And, regarding legibility, I’m not suggesting to have one MonoBehavior per state, the states can be nested classes inside of the main FSM. This way you share what you want in the main, and each state can keep its internal stuff nicely encapsulated if it needs to, override only the callbacks it needs, etc. The main will only ever need to call currentState.Update() etc, so roughly the same cost as a delegate I’d guess.
Again, it’s just that the benefits seem slim… method names are open to typos… plus doesn’t reflecting & caching all the delegates increase load time? (& mem usage but let’s not be picky
I guess my point is, what does an inheritance approach NOT provide?
May 6, 2013 - 10:18 am
No you’re right, I’d forgotten optimisations for enum switches.
So I built an inheritance framework first and I built this because it improves the speed of my programming and reduces the number of errors I make. Given I’m used to having to write special “convention” methods in Unity I don’t find a significant problem to write them correctly.
* Multiple classes with the same method names, requires checking as to which class you are in, or they are in separate files and the logical flow is split between multiple panes. I prefer convention over inheritance in this circumstance.
* Sharing variables between states is easy and doesn’t require a deep and constantly refactored inheritance structure.
Of course this method is very similar to the one that Unity is providing in it’s standard uses of Update, OnColllisionXXX etc.
May 10, 2013 - 5:05 pm
Hey, great tutorial series. I am still striving to understand everything. But I must say, even the usage of the framework is still confusing to me. I am not complaining, since this framework is free
I consider myself an intermediate to advanced Unity programmer, and I am looking for a simple but efficient FSM framework to use. Don’t know how to qualify yours yet.. =/
May 11, 2013 - 8:42 am
Well this is a tricky section
May 12, 2013 - 11:40 pm
Is StateMachineBehaviourEx the most recent version of the state machine?
I’m having a problem when I set state to Dead occasionally the Dead_EnterState doesn’t get called.
I assigned each of my spawned objects an ID and then printed a debug message as the first line in Dead_EnterState with the ID. When the problem occurs I do not see the ID message printed.
I’m probably spawning about 45 objects. When the problem occurs (so far) it only happens to one object out of the group.
Dead_UpdateState gets called and if I set a breakpoint in there I can see that Dead_EnterState is setup as a method to be called but for some reason it doesn’t get called.
It doesn’t happen every time so it’s pretty difficult to track down.
Any thoughts?