State Machine: Child Inheritance + Extension

I am trying to see if there is a way to set up a state machine that can inherit a lot of states (and their functionality) from the parent class, while being able to extend and add additional states in the child class. Thanks in advance for the help, I’ve been stuck for a while.

I have monster AI controlled through a state machine. I have a monster parent class, with a monsterSkeleton child class.

The base monster class will have some states that every monster will have
stateIdle
stateDead

The skeleton child class will use the base states as well as a few new ones
stateSkeletonAttack
stateSkeletonWalk

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Example code of things I’ve tried.

Enum’s. The problem with this is I do not know of a way to extend the enum and add additional states to it.

enum State{Idle, Dead};

Property switches: The problem I am having with these is that I do not know how to extend the functionality in the child to allow for additional states while keeping the parent functionality. This code below is for the parent monster class with it’s base 2 parent states… but not sure how to extend it to add additional states to the switch.

State state
{
   get
   {
      return _state;
   }
   set
   {
      _state = value;
      if(_state == State.Idle)
      {
         //do something
      }
      else if(_state == State.Dead)
      {
         //do something
      }
   }
}

I think you are approaching this the wrong way. Instead of using inheritance to add states, use composition: think of your states as items in a list. You can add more items to the list to increase the complexity of the state machine.

Create your state machine so that it can keep track of potential states and a single active state. Use the state machine to invoke the active state and transition to a new state is the active state is finished.

There is a pretty good example how you might do this on the wiki:
http://wiki.unity3d.com/index.php/Finite_State_Machine

4 Likes

Thanks. Digesting this and I’ll try.

I think I got something that is working.

That reference helped a lot. I cannot use it exactly because it uses enums which doesn’t allow the child to add additional child enum’s for additional transitions/states. However, I pulled what I could from it and here is where I am at. It seems to work OK.

My goals for the state machine:
-Have base states in parent monster class with base functionality (i.e. idle, patrol, die, etc.)
-Have base states in parent monster class that are overrideable if the default functionality needs to be changed or extended
-Have additional child states that can be added to the list of possible parent states that are specific to that child monster.

using UnityEngine;
using System.Collections;

public abstract class Monster : MonoBehaviour
{
    private State _state;
    protected State StateNotInitialized;
    protected State StateIdle;
    protected State StateDead;

    protected virtual void Awake()
    {
        StateNotInitialized = new State(null, null, null, null); //state before it is initialized
        StateIdle = new State(OnStateIdleEnter, OnStateIdleExit, null, null); //idle state that all monsters will have
        StateDead = new State(OnStateDeadEnter, null, null, null); //death state that all monsters will have
        _state = StateNotInitialized;
        state = StateIdle;
    }

    protected virtual void Update()
    {
        _state.OnUpdate();
    }

    protected virtual void FixedUpdate()
    {
        _state.OnFixedUpdate();
    }

    protected State state //getSet
    {
        get
        {
            return _state;
        }
        set
        {
            if(_state != value) //value has changed
            {
                _state.OnStateExit(); //exit old state
                value.OnStateEnter(); //enter new state
                _state = value;
            }
        }
    }

    protected class State
    {
        public delegate void DelegateVoid(); //signature of function
        private DelegateVoid OnStateEnterEventSender;
        private DelegateVoid OnStateExitEventSender;
        private DelegateVoid OnStateUpdateEventSender;
        private DelegateVoid OnStateFixedUpdateEventSender;

        public State(DelegateVoid OnStateEnterEvent, DelegateVoid OnStateExitEvent, DelegateVoid OnStateUpdateEvent, DelegateVoid OnStateFixedUpdateEvent) //constructor
        {
            OnStateEnterEventSender = OnStateEnterEvent;
            OnStateExitEventSender = OnStateExitEvent;
            OnStateUpdateEventSender = OnStateUpdateEvent;
            OnStateFixedUpdateEventSender = OnStateFixedUpdateEvent;
        }

        public void OnStateEnter()
        {
            if(OnStateEnterEventSender != null) //at least 1 listener
            {
                OnStateEnterEventSender.Invoke();
            }
        }

        public void OnStateExit()
        {
            if(OnStateExitEventSender != null) //at least 1 listener
            {
                OnStateExitEventSender.Invoke();
            }
        }

        public void OnUpdate()
        {
            if(OnStateUpdateEventSender != null) //at least 1 listener
            {
                OnStateUpdateEventSender.Invoke();
            }
        }

        public void OnFixedUpdate()
        {
            if(OnStateFixedUpdateEventSender != null) //at least 1 listener
            {
                OnStateFixedUpdateEventSender.Invoke();
            }
        }
    }

    protected virtual void OnStateIdleEnter()
    {
        Debug.Log("OnStateIdleEnter");
    }

    protected virtual void OnStateIdleExit()
    {
        Debug.Log("OnStateIdleExit");
    }

    protected virtual void OnStateDeadEnter()
    {
        Debug.Log("OnStateDeadEnter");
    }
}
using UnityEngine;
using System.Collections;

public class MonsterSkeleton : Monster 
{
    protected State StateAttack;

    protected override void Awake()
    {
        base.Awake();
        StateAttack = new State(OnStateAttackEnter, OnStateAttackExit, OnStateAttackUpdate, null);

        state = StateAttack;
    }

    protected override void OnStateIdleEnter()
    {
        Debug.Log("OnStateIdleEnter override: Child does something different than parent method"); 
    }

    protected override void OnStateIdleExit()
    {
        base.OnStateIdleExit();
        Debug.Log("OnStateIdleExit override: Child adds additional functionality on top of parent method"); 
    }

    protected void OnStateAttackEnter()
    {
        Debug.Log("OnStateAttackEnter"); 
    }
   
    protected void OnStateAttackExit()
    {
        Debug.Log("OnStateAttackExit"); 
    }

    protected void OnStateAttackUpdate()
    {
        Debug.Log("OnStateAttackUpdate"); 
    }
}

I still don’t think you want to be using inheritance for this at all but … I do agree the enums are a bit clumsy. I think we can extract the dependency that the state machine has on the states by using a generic method to transition between states.

Instead of having a base machine which contains some built in states I think it makes sense to have a machine with no states at all. The state machine should provide an interface for changing the current state and send signals to whichever state is active. Finally, each state can handle the state transitions by calling the state machine’s change state method. If you use a generic signature, the state can describe it’s transitions directly in code. Excuse any compile errors, I’m programming “from the hip” but this is what I’m thinking:

class StateMachine : MonoBehvaiour
{
  State Current { get; set; }
  State Current { get; set; }
  Dictionary<Type, State> stateDictionary = new Dictionary<Type, State>();
  public void TransitionState<T>() where T : State, new()
  {
    if (!stateDictionary.ContainsKey(typeof(T)))
      stateDictionary.Add(typeof(T), new T().Init(this));

    Current.OnExitState();
    Current = stateDictionary[typeof(T)];
    Current.OnEnterState();
  }

  void Update()
  {
    Current.OnUpdate();
  }
}

class State
{
  protected StateMachine machine { get; set; }
  public State Init(StateMachine machine)
  {
      this.machine = machine;
      return this;
  }

  public virtual void OnEnterState() { }
  public virtual void OnExitState() { }
  public virtual void OnUpdate() { }
}

class Idle : State
{
  public override void OnUpdate()
  {
      //determine if player is nearby
      if (playerNearby)
          machine.TransitionState<Chase>();
  }
}
1 Like

Really, no is a problem. You can override enum State in derived class. For example:

public class Monster : MonoBehaviour{

public enum State{Idle, Dead};

}

And add or remove states in derived classes, inheriting state methods:

public class Monster2 : Monster{

public new enum State{Idle, walk, run};

}
1 Like

Even though this will compile, I don’t think it is what we’re looking for. Using the new keyword like this hides the inherited enum, it does not override it. Methods in Monster2 will see the new enum but methods in Monster will not. Monster2 will not be able to take advantage of any of the behavior inherited from Monster because Monster.State.Idle is fundamentally different from Monster2.State.Idle.

2 Likes

new Modifier (C# Reference)

Ok, exactly, new modifier hides (does not override) a public or protected member(variables and methods) that is inherited from a base class.

Nor is exactly necessary to create virtual or abstract methods, to be modified in derived classes.

That is, you can:

public class Monster2 : Monster{
public new enum State{Idle, walk, run}; //Hide inherited enumeration.
public new void HideIdleMethod(){} //Hide inherited method
}
1 Like

What @eisenpony is saying is that if you have something like this:

public class Monster : MonoBehaviour{
public enum State{Idle, Dead};
}

[LIST=1]
[*]public class Monster2 : Monster{
[*]

[*]public new enum State{Idle, walk, run};
[*]

[*]}
[/LIST]

Then you do this:

public class MyClass : MonoBehaviour{

public Monster monster;

}

And you drag a Monster2 in it, then you won’t have access to Monster2’s state. Only Monster’s.
With hiding you need a direct reference to the class to access the variable / method and not the base class.

1 Like

Careful there.

If you have this scenario:

public class Foo
{

   public void DoSomething()
   {
     Console.WriteLine("I am a Foo");
   }

}

public class Bar
{
   
   public new void DoSomething()
   {
     Console.WriteLine("I am a Bar");
   }
   
}

And you do:

Bar a = new Bar();
a.DoSomething();

Foo b = a;
b.DoSomething()

With the ‘new’ modifier, you’ll still get:

Because the method accessed is controlled by the type you reference it as.

Where as with an override:

public class Foo
{

   public virtual void DoSomething()
   {
     Console.WriteLine("I am a Foo");
   }

}

public class Bar
{
   
   public override void DoSomething()
   {
     Console.WriteLine("I am a Bar");
   }
   
}

If you did the same thing, you’d get:

In a state machine, the state controller will probably be accessing each state by some base type. So when it calls any methods, it’ll be calling the method on that base type. Not the ‘new’ method.

1 Like

Thanks for the help guys.

My goal is to be able to have a state like OnStateDeathEnter that has base parent functionality such as adding 1 to the kill counter, disabling the monsters collider, etc. But for a child I’d like to be able to expand on this base parent functionality and do things like play a sound on death, or create an explosion of guts, etc. The only way I know how to do this is to have the OnStateDeathEnter a virtual method in the parent monster class. This can get messy though. Is there a better way to do this?

Reading through the links and code posted there are 2 general ways I am seeing to do state machines.

Option 1:
-State is a parent abstract class. You have child states that inherit from state like StateIdle :: State, or StateDeath :: State.
-You have a FSM to manage the current state and transitions
-The functionality of state transitions are built into the state child class.

Option 2:
-State is a class that calls events. You have multiple instances of the State class that point to different OnStateEnter/Exit event methods.
-You have a FSM to manage the current state and transitions (I’m just using a getter/setter property)
-The functionality of state transitions are methods in the monster class and/or monster child class.

Option 1 seems cleaner because behaviors can be bundled up and packaged with the child state class. Also it’s nice to have a list of only the list of states that you will use. With option 2 every monster state behavior will have to be part of the monster parent/child class and it will be messy. But with option 2 the OnStateEnter/Exit methods are inherited and can be tweaked and customized by the child which is critical for my game.

I think the way to go is to use inheritance only on the states, not on the machine. Leave the machine as simple as possible.

I would start by creating unique states for each monster and lifting the common components up into abstract states as they become obvious. Perhaps something like this:

namespace AI.Monsters.Common
{
  class State
  {
    protected StateMachine machine { get; set; }
    public State Init(StateMachine machine)
    {
        this.machine = machine;
        return this;
    }

    public virtual void OnEnterState() { }
    public virtual void OnExitState() { }
    public virtual void OnUpdate() { }
  }
}

namespace AI.Monsters.RockGolem
{
  class Idle : State
  {
  public override void OnUpdate()
  {
      // Do Golemy stuff
      var playerDistance = player.position - gameObject.position;
      var playerNearby = playerDistance.sqrMagnitude < 10*10;
      if (playerNearby)
          machine.TransitionState<RockGolem.Chase>();
  }
}

namespace AI.Monsters.Treeant
{
  class Idle : State
  {
    public override void OnUpdate()
    {
      // Do Treanty stuff
      var playerDistance = player.position - gameObject.position;
      var playerNearby = playerDistance.sqrMagnitude < 15*15;
      if (playerNearby)
          machine.TransitionState<Treeant.Chase>();
    }
  }
}

Now I notice that these two Idle classes are very similar, so I can extract the common code.

namespace AI.Monsters.Common
{
  abstract class Idle : State
  {
    public override void OnUpdate()
    {
        var playerDistance = player.position - gameObject.position;
        var playerNearby = playerDistance.sqrMagnitude < SqrVisionDistance;
        if (playerNearby)
            Chase(player);
    }
    protected abstract int SqrVisionDistance { get; };
    protected abstract void Chase(GameObject target);
  }
}

namespace AI.Monsters.RockGolem
{
  class Idle : Common.Idle
  {
    public override void OnUpdate()
    {
      // do Golemy stuff
      base.OnUpdate();
    }

    protected override int SqrVisionDistance
    { get { return 10*10; } }

    protected override void Chase(GameObject target)
    {
      machine.TransitionState<RockGolem.Chase>();
    }
  }
}
// etc...
1 Like

Ah that looks perfect. Thanks.