Implementing finite-state-machine AI. (C#)

I was reading this book about state driven AI(Programming Game AI By Example) which clearly explains the structure, however it does so in C++.

I want to re-create this structure, however I’m having a plethora of problems already. This is especially complicated for me because I usually do everything in JS.

(Basic structure)

And here’s my code so far:

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

//Imagine that every class here only has a single instance. A singleton without the actual implementation.

public class AI : MonoBehaviour {
    Human human;
    // Use this for initialization
    void Start () {
        human = new Human(); //You are trying to create a MonoBehaviour using the 'new' keyword.  This is not allowed.  MonoBehaviours can only be added using AddComponent().  Alternatively, your script can inherit from ScriptableObject or no base class at all.

//Well, Human inherits AI which inherits MonoBehaviour.

//I thought however that inheritance only inherits and doesn't create a new instance. But now that I think about it, that wouldn't make sense.

//What is the work-around for this problem? I can't fathom one at the moment.

        human.Start ();
    }
  
    // Update is called once per frame
    void Update () {
        human.Update();
    }
}



class Human : AI{
    StateMachine stateMachine;
    internal void Start(){
        stateMachine = new StateMachine ();

        stateMachine.Start ();
    }

    internal void Update(){
        stateMachine.Update ();
    }
}



class StateMachine:Human{
    State state;
    public pointer globalState; //A pointer to the current instance of any State class that the AI is currently in.
  
    internal void Start(){
        state = new State ();
    }

    internal void ChangeState(/*pointer*/){ //Pointer to a state's class instance.
        //globalState = /*pointer*/
    }

    internal void Update(){
        //state.Execute(globalState);
    }
}

class State:Human{
    internal void Enter(){

    }

    internal void Execute(/*delegate*/){
        //delegate.Execute;
    }
}

class Idle:State{
    internal void Enter(){
        //Do whatever when starting this state.
    }

    internal void Execute(){
        //Do whatever Idle state does.
    }

    internal void Exit(){
        //Do whatever when exiting this state.
    }
}

So, as you can see there are 2 problems here. The pointer one(which can be solved using a string for the state and a getter that returns the instance of said state. But I didn’t try doing this yet, and it wouldn’t be as elegant.) and the cannot create MonoBehavior(I still want all the state classes to be able to access the MonoBehavior freely.)

So, C# Gurus, what kind of code structure would I have to implement in order to make this kind of higher structure possible? I can’t think of anything that would accommodate for the structure described in the book, but then again I’m very new at C# as a whole.

Thanks.

Don’t derive StateMachine from Human.

Also, ignore the notion of “pointer” in C#, everything is a pointer, you just don’t have to deal with up/down casting.

You’re confusing yourself with the many C+±isms in the original code, e.g. trying to shoehorn pointers into a language that doesn’t have such a construct (as @LightStriker_1 ) already pointed out.

Game AI by Example is an excellent book, but I would take the concepts and skip the actual implementation. You don’t need to implement your own state machine code as there are already a few options out there that will do that for you. PlayMaker is one example that is built specifically for Unity and allows for visual design of states, transitions and actions.

There’s also an open source library for C# called Stateless that does a great job of implementing FSMs in C#. I have used in the past with Unity and found it to be powerful and bug-free.

I also wrote my own library called TinyStateMachine which is even simpler and more lightweight (just one C# file), which is based on writing state transition tables directly in code. But I couldn’t be bothered to document it except by writing a few unit tests.

TL;DR: Finite State Machines are good. Game AI by example explains the concepts well, but more elegant implementations can already be found for C#.

I see. Thanks for the replies guys.

I looked at some of the libraries and I don’t think they’d suit me at the moment. They add a lot of complexity which I have no control over, and I don’t understand them very well.

I really do understand and like the structure that is in the OP. However, I have still found no way to do that. Shame indeed.

I have found other implementations, particularly in this stackoverflow thread (Simple state machine example in C#? - Stack Overflow)

I however fail to see how they’re different from a bunch of ‘if’ and ‘switch’ statements.

What I like about the structure in the OP is that it is very hierarchical and thus manageable and easy to understand(for me.)

I’ll post here once I find out what thing I’ll do.

Maybe your first a.i. should be something less complicated than a human. Try making a statemachine for something not even intelligent. How about a door or a light? It’ll get you used to whatever you’re unfamiliar with and get you in the right mindset to make a state machine.

I myself as a programmer for over a decade now find using PlayMaker a fun way to organize code into a series of state machines. It’s cool to visualize and fun to use, and ridiculously easy to make changes to. But since that’s money, here’s what I would do for a door by implementing my own little state machine.

enum States{closed, opening, open, closing}
int doorState = States.closed;

...

switch(doorState)
{
    case States.closed:
    //execute closed code & listener for interaction
    break;
    case States.opening:
    //execute code for animating the door open, switch to open when done
    break;
    case States.open:
    //listening code for event to close door
    break;
    case States.closing:
    //code to animate door closed and switch to closed state
    break;
}

Well, that kind of implementation is simple. I’ll give it a try. Although, I wouldn’t want to continue with this kind of implementation.

But, to give everyone a broad idea of what I’m doing - I’m just making a stealth-game prototype.

And I have a script within each human that is called ‘DetectBear’, this script is in each Human. The script ‘AI’ is also in each human. Each human also contains 2 trigger colliders, which both contain scripts that simply return a list of objects that are within those colliders.

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

public class DetectBear : MonoBehaviour {

    private GameObject bear;
    private LayerMask mask;
    //private PolygonCollider2D polygonCol;
    private whoIsInside insideScriptImmidiate;
    private whoIsInsideLong insideScriptLong;
    private bool bearDetected = false;

    private List<GameObject> listImmediate;
    private List<GameObject> listLong;
    private RaycastHit2D ray;
    // Use this for initialization
    void Start () {
        bear = GameObject.Find ("Bear"); //Gets our player.
        mask = ~(1 << LayerMask.NameToLayer ("FoV")); //Gets FoV layer and puts it into mask so that we ignore the FoV layer.
        //polygonCol = transform.Find("FoV").GetComponent<PolygonCollider2D>(); //Gets FoV polygon within the 'FoV' gameobject which contains it.
        insideScriptImmidiate = transform.Find("FoVImmediate").GetComponent<whoIsInside>(); //Get who is inside script within FoVImmediate.
        insideScriptLong = transform.Find("FoVLong").GetComponent<whoIsInsideLong>();
    }
   
    // Update is called once per frame
    private float timerThreshold = 3f; //Time.Delta is in seconds, so is this.
    private float timer = 0f;
    void Update () {
        listImmediate = insideScriptImmidiate.getList ();
        listLong = insideScriptLong.getList ();

        ray = Physics2D.Raycast(transform.position,
                                            bear.transform.position - transform.position,
                                            Mathf.Infinity,
                                            mask); //Draw ray from Human to Bear.

        if(listLong.Contains(bear) && ray.collider.gameObject == bear){//If bear is in range and visible.
            if(listImmediate.Contains (bear)){
                bearDetected = true;
            } else if(listLong.Contains (bear)){
                timer += Time.deltaTime;

                if (timer > timerThreshold) {
                    bearDetected = true;
                }else{
                    Debug.DrawRay (ray.point, (new Vector3 (ray.point.x, ray.point.y, 0) - transform.position) * -1, Color.yellow);
                }
            }
        }else{
            timer = 0f;
            bearDetected = false;
        }

        if (bearDetected) {
            Debug.DrawRay(ray.point, (new Vector3(ray.point.x, ray.point.y, 0) - transform.position) * -1, Color.green);
            gameObject.GetComponent<AI>().setState(AI.States.panick);
        }
    }
}

This basically detects the bear in one of the two ways. And as you can see, it also has an if statement at the end that just draws a green ray if the bear is detected, which also changes the state of that particular human. In the future, I’d like a ‘global’ controller script that will set the state of a human based on its instance id. But, that is not needed right now.

And here’s the AI script:

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

public class AI : MonoBehaviour {
    public enum States{idle, panick}
    States state = States.idle;
    // Use this for initialization
    void Start () {

    }
   
    // Update is called once per frame
    void Update () {

        switch (state) {
            case States.idle:
                Debug.Log ("I'm idle.");
                break;
            case States.panick:
                Debug.Log ("I'm panicking.");
                break;
        }

    }

    public void setState(States s){
        state = s;
    }
}

I like this implementation, except for the switch statement. I want small, manageable chunks of code that are easy to follow.

So, this AI structure and path finding is left. But, I’m stuck at the AI structure right now, especially since I’ve never done this type of thing before.

Finite State machines are all about them switches, bro :stuck_out_tongue:

Your code will not get more complicated than you see it there. Another class can contain definitions for what needs to be done by each state, and your class you have there can just be the state machine itself. The key will be to design your algorithms to run in single steps, to also match the design of state machines.

Action
Goal test
Success / fail / other event event where you switch states and set values

I implemented a FSM based on the concepts in Programming Game AI By Example. From memory the main point of his code was to keep the states as separate classes from the state machine. It went something like this. Be aware this is all just from memory, and may not work properly.

The state machine code. I seem to recall needing to abstract this one step further for flexibility. IE this was a regular C# class owned by a MonoBehaviour. But you should be able to see the general structure here.

public class StateMachine : MonoBehaviour {
    private State currentState;

    public void SwitchState (State newState){
        currentState.EndState(this);
        currentState = newState;
        currentState.BeginState(this);
    }

    void Update (){
        if (currentState != null){
            currentState.UpdateState(this);
        }
    }
}

Here is the base class for a State.

public abstract class State {
    public abstract void BeginState(StateMachine stateMachine);
    public abstract void UpdateState(StateMachine stateMachine);
    public abstract void EndState(StateMachine stateMachine);
}

Making the individual states is simply a case of inheriting from the base class.

1 Like

No, it’s not. I never have switch/case in my state machine. Each state is a class, and it’s to each state to determine how and when to change to another state.

2 Likes

That is very true. An abundance of switches is the quickest way to build an unmaintainable state machine.

1 Like

@LightStriker_1 I’ve been under the impression that a simple finite state machine can be implemented with a switch statement. I learned from reading examples (FSMs implemented in C, C++ and Java using switches) and also, a switch seemed to be a sensible way to turn a diagram for an FSM into code.

I’ve made classes just to group relevant methods together, but using those classes as the states sounds like transitions / expanding transitions would be a pain. Wouldn’t they need a reference to each other since the Type is going to be that class?

@Kiwasi is that so? I’ve yet to have a problem. How can someone get disorganized if they’re using enums? :eyes:

–edit

Read your post that I missed after mine. I see, so the state-class thing is the implementation style for that author (maybe others? never heard of it myself). I’ll look into that. I should know these things if I’m going to be a teacher in 3 years, haha.

It’s so easy to find implementation examples that use switches. My learning (for most things) came from tearing apart examples, I’ve never read the ‘proper’ ways in how-to books.

Switches are fine for a machine with 3 or 4 states. However try implementing a nested state machine with a dozen states on each level, plus global transition, state entrance and exit behaviour and multiple state variables. Do this all with switch statements. Then go back and change the behaviour inside one state completely six months later. You’ll get the idea.

Having each state as a separate self contained script has several advantages

  • Easier to read an entire states functionality in one place
  • The base state machine can be reused every where. Simply plug in a new set of states and you are good to go
  • The code complexity does not increase significantly with extra states
  • Changing one state does not effect the others. The system is modular enough that you can replace a state entirely without effecting the system.

There are several other ways to implement a state machine, including graphical (with a tool like playmaker) and an event based system (Unity gems has a good frame work). There are others.

As with any frame work there is a trade off between functionality and complexity. For simple jobs the complexity of a fully fledged state machine is not warranted. If you are making a space invaders style AI then a switch statement is probably good enough. But if you want something like Skyrim then you’ll need to spend a fair bit more time on your frame work.

It really doesn’t take much for a switch/case state machine to become a bloated unmaintainable mess. You ends up having a bit of everything all over the place, methods off different state near each other, and a very hard time to insert or remove a state. This kind of state machine is fine when you know exactly what you need, and it is very unlikely to change later - which the design never does, right?

In one game, I even did a door in object-oriented FSM, and it helped… when the design decided the door could be blocked, slammed, crush the player, destroyed… and not just open, opening, closed, closing.

Once you know how an OO FSM works, which is dead easy really, you won’t go back. OO FSM really starts to shine when the complexity increases, like with any kind of AI. Using polymorphism for your state is a blessing… By example, if you have a collection of state in the air, a collection on ground, a collection underwater, etc. And then you have player, NPC, enemy, and other that can all share the same states, which is simply impossible with switch/case.

@LightStriker_1 I’m sure I’ll figure it out when I get that far. My plan for my doctorate, if I can go with the option, is to make a complex state machine to be a good a.i. of my mother’s favorite dog who will be near death at that point in time. As for your door example, isn’t expanding a switch statement as easy as adding the case to the switch and appending a new state to the enum?

In the event to switch crushed, I would set the state to States.crushed. What you said about them sharing states made me realize my misunderstanding… that’s just because your states are methods xP You can share them because they are the behaviors. If that’s the point, then I get it now. My [probably outdated] idea of a state machine is that a state is more like a label to group actions together with. I can see now that the correct idea for a state machine is that the states are the actions? Or are both valid but the state-class-function idea scales better?

@Kiwasi I have done such with a switch :smile: I went back to a horror game from when I was still new to unity. I added a state to the monster behavior between tracking and killing the player. I added 1 more case to check for the final listen state in which the player might escape if they make no noise.

Maybe I made a flaw in designing my state machine and violated a convention. By making the current state a public variable I could just set it into another state from any point by accessing that variable in the script. And for your fourth point… if you’re adding a new state to happen between two other states, don’t you have to modify the events to transition into that state? Sounds about the same work for having my function choose the new state instead of the previous one. If this should be obvious, then it’s probably a flaw with switch based finite state machines that I overcame by violating a convention for making them :stuck_out_tongue: I wouldn’t know, my top concern has been making things work above all else.

If it works for you, then fair enough. But my experience is that switches turn to spaghetti very quickly.

I guess I’m not explaining myself properly… A state is not a single action; it has properties, it may have multiple methods, and by experience it is very helping to have a kind of constructor/destruction for when the state starts and when it stops. It’s never “as easy as adding an entry in an enum”.

They can be shared not because they are method, but because they are object. Each AI can have its own instance of “NPCWalkState”, while feeding it with its own parameter, like where a NPC can walk, at what forward speed, what turn speed, etc.

Here’s an example of the class hierarchy used in a game I worked on;

Character > Player
Character > NPC
Character > Enemy

State > CharacterState > GroundState > WalkState
State > CharacterState > GroundState > RunState
State > CharacterState > GroundState > SlideState
State > CharacterState > GroundState > StumbleState
State > CharacterState > GroundState > RespawnState
State > CharacterState > AirState > JumpState
State > CharacterState > AirState > DoubleJumpState
State > CharacterState > AirState > DashState
State > CharacterState > AirState > SlamState
State > CharacterState > AirState > DeadState
(and 15 other states like that)

Player, NPC and Enemy have different stats and behaviour. However, they all can use those states;

machine.SwitchState(new JumpState(machine, character));

Example of a state;

public class JumpState : AirState
{
    // Velocity, jump height, and other parameter

    public JumpState(StateMachine machine, Character character)
        : base(machine, character) { }

    public override void Constructor()
    {
        base.Constructor();

        Character.Animator.SetTrigger("Jump");
        Character.Visual.FXHandler.Jump();

        if (Character is Player)
            StatsManager.Instance.Jumped();
    }

    public override void Update()
    {
        UpdateBallisticCurve();

        // Evaluate other possible action in mid air
        if (Character.Jump()) // The character has its own input method for deciding an action
            Machine.SwitchState(new DoubleJumpState(Machine, Character));

        if (Character.Dash())
            Machine.SwitchState(new DashState(Machine, Character));

        if (Character.Slam())
            Machine.SwitchState(new SlamState(Machine, Character));

        if (IsGrounded()) // IsGrounded is a method of AirState
            Machine.SwitchState(new RunState(Machine, Character));
    }

    public override void Destructor()
    {
        Character.Visual.FXHandler.StopJump();
    }

    private void UpdateBallisticCurve()
    {
        // Jump logic
    }
}
1 Like

Execution wise? Without a doubt lol. If the behavior is very complex and cannot be broken up, it’s entirely up to knowing what enum to search for in your giant switch xD But if the methods are broken up and designed like PlayMaker state machines, your class can be just the switch. Then if you’ve got a case, method call and break, managing 100 states would be 300 lines.

@LightStriker_1 it’s still sounding like a design thing to me. That point regarding the ease of expansion sounds unfortunate. I’ll ask a few of the cs graduates about state machines, they might be able to explain it better since they know me lol.

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

public class AI : MonoBehaviour {
    StateMachine stateMachine;

    void Start () {
        stateMachine = new StateMachine(this);
        stateMachine.addState ("Idle", new State_Idle (this));
        stateMachine.addState ("Panick", new State_Panick (this));
    }

    void Update () {
        stateMachine.Update ();
    }
}

public sealed class StateMachine{
    AI ai = null;

    public StateMachine(AI t)
    {
        ai = t;
    }
   
    //////////////////////////////////////////////////////////
    public AI GetAI(){
        return ai;
    }
    //////////////////////////////////////////////////////////
    Dictionary<string, State> states = new Dictionary<string, State>();

    public void addState(string s, State o){
        states.Add(s, o);
    }

    public object getState(string s){
        return states[s];
    }

    public void Update(){
        foreach(KeyValuePair<string, State> state in states)
        {
            state.Value.Update();
        }
    }
}

public abstract class State
{
    public string Name { get; set; }

    public abstract void Entry();
    public abstract void Update();
    public abstract void Exit();
}

class State_Idle : State{
    string Name = "Idle";
    AI ai = null;

    public State_Idle(AI t){
        ai = t;
    }

    public override void Entry()
    {
        Debug.Log("Idle Entry");
    }

    public override void Update()
    {
        Debug.Log("Idle Update");
    }

    public override void Exit()
    {
        Debug.Log("Idle Exit");
    }
}

class State_Panick : State{
    string Name = "Panick";
    AI ai = null;

    public State_Panick(AI t){
        AI ai = t;
    }
   
    public override void Entry()
    {
        Debug.Log("Panick Entry");
    }
   
    public override void Update()
    {
        Debug.Log("Panick Update");
    }
   
    public override void Exit()
    {
        Debug.Log("Panick Exit");
    }
}

This is my solution thus far. I’m happy with in, and I hope it will be sustainable and won’t need any changes in the future.

This is only the bare-bones structure, I obviously didn’t add anything to it yet.

How long have you been in this business for? Everything requires changes :slight_smile: