AI State Machine Tutorials: Tutorial #2

September 25, 2019

Tutorial #2

From Blog Post: Unity Basic AI State Machine Tutorials

Youtube – Unity 3D – Make a Basic AI State Machine

Tutorial #2

By: Joey The Lantern


General Structure

There is a general state machine class, a class for each individual state, and then the class for whatever will be using these states. This format is very similar to the first AI state machine tutorial I followed by UnityCollege3D.

State Machine

They created a new namespace, StateStuff. This was because they did not want anything to be a monobehaviour. This namespace then holds the StateMachine class as well as a public abstract class State. They mention that could be used in place of to allow you to specify what types can use this class, but they went with because it’s more ambiguous and works with more things. This is something I will need to look into, but I am guessing at this point T just means any type. So basically anything can use the StateMachine.

The state machine class was given two variables, State currentState and T Owner. These are both set in a constructor for StateMachine. Owner is what will be using the state machine, and currentState is obviously what state it is currently in.

State Class (within StateMachine script)

There were several abstract methods created for this class. These were: EnterState, ExitState, and UpdateState. EnterState allows you to perform actions immediately upon entering a new state, ExitState performs actions necessary when leaving a state for another, and UpdateState performs the various update actions for that state on that object.

FirstState

This class inherits the State class in the StateStuff namespace. The State here takes in an AI reference (again, I need to look into this more to see what this is actually doing). I see what this is doing better after implementing the abstract class. The type that is passed into State is then the type required by all of the methods that take in a parameter of type T. So since we declared State, now all of the methods require an input of AI _owner (translated from T _owner).

Their general idea is that there is only one instance of each independent state class, and every object that wants to use this state will just reference this same single instance. Following that, they use a bit more of an involved singleton-looking pattern to create this. The setup is the following:
public class FirstState : State
{
private static FirstState _instance;

private FirstState()
{
if (_instance != null)
return;

_instance = this;
}

public static FirstState Instance
{
get
{
if(_instance == null)
{
new FirstState();
}

return _instance;
}
}
}

The second state is exactly the same as the first, it just changes some of the text around so that it matches the new class name.

AI Class

This class represents the main script that would be running on your object that you would like to be using AI. To show the state machine working with it, it simply has a timer in the Update method that changes a bool.

GENERAL FLOW

There is one StateMachine instance and one instance of each individual state class. Each state has an UpdateState method, which generally corresponds with what an object in that state should be doing with an Update method. This is actually called through the StateMachine’s Update method though for every object.

The class which you want to use with the StateMachine and various States (AI in this example) must first reference the StateMachine and pass itself in as a paramter. Then it just needs to make sure to call stateMachine.Update within its own Update method. This is what allows everything to communicate what an object using this state machine should actually do in that state.

Finally, each individual state class is responsible for determing when to change to a new state, and what that new state should be. This is however performed by using the ChangeState method found within the StateMachine class. This method is responsible for calling the ExitState method from the old class, and the EnterState method from the new class.

FINAL NOTES

This setup uses a single instance of a state machine and a single instance for each state, which can be a nice avenue to take since it can really keep things scaled down that way. It also seems nice that the classes simply using this StateMachine setup mostly just need to call the StateMachine’s Update method to really interact with it. It helps keeps them from getting messy with state machine code. It does seem like it could be a bit tricky making sure the individual states themselves have proper references to check within the AI classes to figure out when they should change states with this approach.