Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Types for a state machine controller

Discussion in 'Scripting' started by abeck12390, Aug 24, 2023.

  1. abeck12390

    abeck12390

    Joined:
    Apr 12, 2023
    Posts:
    3
    I am using finite state machines to control entities in my game and I have a state machine class that handles the switching of states. I have an abstract class of EntityState that the player states, enemy states, etc. would inherit from so that I don't have to retype of bunch of shared logic. I have the StateMachine class storing the current state as an EntityState since the state machine will be dealing with many type of states like PlayerState and all of the EnemyStates.
    Code (CSharp):
    1. public class StateMachine
    2. {
    3.     public EntityState CurrentState { get; private set; }
    4.  
    5.     public void Initialize(EntityState startingState)
    6.     {
    7.         CurrentState = startingState;
    8.         CurrentState.Enter();
    9.     }
    10.  
    11.     public void ChangeState(EntityState newState)
    12.     {
    13.         CurrentState.Exit();
    14.         CurrentState = newState;
    15.         CurrentState.Enter();
    16.     }
    17. }
    If I ever need to call a function on the current state (regardless of what the current state is) from another script I need to reference the current state from the state machine

    Code (CSharp):
    1. StateMahcine.CurrentState.SomeFunction()
    My issue is that if I ever need to call a function from a derived class (for example PlayerState which is an abstract base class for all my player states) that doesnt exist on EntityState it will fail because the state machine is storing the current state as EntityState and not PlayerState. I could get around this by making many StateMachine child classes that each store the current state as whatever state I need. But I dont want to do this as every time I need to add a new type of enemy or something that uses a FSM I need to add another class.

    So my question is that is there a way to change the type of currentstate or store it as a certain type? I would like to tell the StateMachine what type base class to store current state as when it starts. I tried doing this with generics in the constructor but from what I've read you cant use generics types in a constructor.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    FSM finite state machines:

    I suggest never using the term "state machine." Instead, just think:

    - I have to keep track of some THING(s)
    - That THING might change due to reasons
    - Depending on that THING, my code might act differently

    That's it. That's all it is. Really!! The classic example is a door:

    - track if it is open or closed
    - if it is open, you could close it
    - if it is closed, you could open it
    - if it is open you could walk through it
    - if it is closed you could bump into it

    Wanna make it more complex? Put a latch on one side of the door.

    This is my position on finite state machines (FSMs) and coding with them:

    https://forum.unity.com/threads/state-machine-help.1080983/#post-6970016

    I'm kind of more of a "get it working first" guy.

    Ask yourself, "WHY would I use FSM solution XYZ when I just need a variable and a switch statement?"

    All generic FSM solutions I have seen do not actually improve the problem space.

    Your mileage may vary.

    "I strongly suggest to make it as simple as possible. No classes, no interfaces, no needless OOP." - Zajoman on the Unity3D forums.
     
  3. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    You really just gotta answer the question sometimes Kurt.

    You can just to a type check and fetch it with a TryGet pattern:
    Code (CSharp):
    1. public class StateMachine
    2. {
    3.     public EntityState CurrentState { get; private set; }
    4.    
    5.     public bool TryGetEntityState<T>(out T state) where T : EntityState
    6.     {
    7.         state = EntityState as T;
    8.         return state != null;
    9.     }
    10. }