Search Unity

State machine help

Discussion in 'Scripting' started by rizenmusic, Mar 24, 2021.

  1. rizenmusic

    rizenmusic

    Joined:
    Oct 2, 2019
    Posts:
    23
    Hi! That would be my third try to get help on State Machines) A guy pointed out to scripting forum so here I am.

    So, I'm trying to understand (first) and implement (second) a state machine to my game. I (probably) understand how inheritance works but can't get how to change states and where they are located.

    So here is what I need for my simple Finite State Machine:



    What I don't understand here:

    Where should all my state scripts be and how do I change them during runtime? What should inherit from what? State class, in my mind, should inherit from monobehaviour to get access to Update and FixedUpdate, AttackState should inherit from State to override it's methods, the other is unknown.

    Any help please?)
     
  2. Lekret

    Lekret

    Joined:
    Sep 10, 2020
    Posts:
    358
    MonoBehaviour is ok choice. I like when my FSM controls everything, changes states, updates them, you have more control and don't need to disable/enable state MonoBehaviour which can affect coroutines, OnEnable/OnDisable etc. This is probably how your FSM should look like and how I used to write them. Hope this will help.
    Code (CSharp):
    1. class FiniteStateMachine : MonoBehaviour
    2. {
    3.     public State currentState;
    4.  
    5.     private void Start()
    6.     {
    7.         currentState.OnEnter();
    8.     }
    9.  
    10.     private void Update()
    11.     {
    12.         foreach(var state in currentState.NextStates)
    13.         {
    14.             if (state.RequireTransition())
    15.             {
    16.                 currentState.OnExit();
    17.                 state.OnEnter();
    18.                 currentState = state;
    19.                 break;
    20.             }
    21.         }
    22.  
    23.         currentState.OnUpdate();
    24.     }
    25. }
    You just need an object with FSM and all states, then you need to set current state and nextStates array for every state, to which states it can transit.
     
    Last edited: Mar 24, 2021
    rizenmusic likes this.
  3. rizenmusic

    rizenmusic

    Joined:
    Oct 2, 2019
    Posts:
    23

    That's how my FSM class looks right now:

    Code (CSharp):
    1. public class FSM: MonoBehaviour
    2. {
    3.     public StateHandler currentState { get; private set; }
    4.  
    5.     private void Start()
    6.     {
    7.         currentState.OnEnterState();
    8.     }
    9.  
    10.     public void ChangeState(StateHandler newState)
    11.     {
    12.         currentState.OnExitState();
    13.         currentState = newState;
    14.         currentState.OnEnterState();
    15.     }
    16. }
    Do you mean having my FSM and scripts as components or as child objects?
     
  4. Lekret

    Lekret

    Joined:
    Sep 10, 2020
    Posts:
    358
    By child objects you mean child GameObject for every single state? No, keep them as components, if you have some kind of Player GameObject with Collider, Health, Movement etc. Just make child GameObject to this Player GameObject and put FSM with all states on it.
     
    rizenmusic likes this.
  5. rarac

    rarac

    Joined:
    Feb 14, 2021
    Posts:
    570
    your problem seems to be that you want to have states in different scripts without actually attaching those scripts to the object.

    You have to make a choice, either you have all your code in 1 script and you only need that one script attached to the object, or

    2) you have multiple scripts, but you need to add them all as components
     
    rizenmusic likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,736
    Getting a complex state machine operational is something that you DO NOT want to mix with inheritance if you are presently writing things like "I (probably) understand how inheritance works"

    Just hard-wire the entire thing and tweak it until it gives EXACTLY the behavior you want. That's obviously the acid test... it has to first function 100% perfect as you envision it, otherwise what's the point?

    In my experience, EVERY single general purpose FSM implementation I have used (without exception) has been a hack and a half and brings almost ZERO value to the table as far as solving the actual issue I want to solve.

    Writing "general purpose FSM frameworks" is really more of a "Lessons we do in CS-101 in our first year of college" than anything that actually provides legitimate value.

    It always seems more straightforward to just write the state machine you need now, rather than try to make some mythical "state machine framework" set of classes that you can use forever and into the future.

    Besides, almost all interesting production-scale state machines have multiple orthogonal (or semi-orthogonal) axes of state, and capturing that in a generic state machine hierarchy is incredibly hard and often makes the resultant implementation sub-optimal and extremely brittle, forcing it to embody all the inherent limitations (stated and emergent) of the framework itself.
     
  7. rizenmusic

    rizenmusic

    Joined:
    Oct 2, 2019
    Posts:
    23
    Interesting information. I'm not trying to implement a general purpose state machine, I just want my FSM to handle my AI and player controller. For AI it is a much needed thing because my game is going to have bosses with different behaviours and even simple enemies can have like 4-5 different states which is a pain to debug and read via enum/switch system I'm using right now. So I want to learn how it works and how to build one. I've got Playmaker which is built on FSM, but want to learn this particular thing myself.

    Looks like you've got a lot of experience, why do you say that inheritance is bad for this? Almost every youtube tutorial on this theme uses it. Also handwiring thing doesn't look very clear to me because I'm just a 2 months junior so manu concepts are still elusive to me.
     
  8. rizenmusic

    rizenmusic

    Joined:
    Oct 2, 2019
    Posts:
    23
    I finally did it. The main mistake I made is that I thought that every script I add to my gameObject would run simultaniously which is not true. It's finally working so if anybody needs a simple and working solution - here it is:

    I have 4 main classes that sit on my gameObject, every one is monobehaviour, so you can run your Unity methods just fine:

    FSM, blueprint which changes states and runs update and fixedUpdate methods for State class.
    State, blueprint which runs virtual methods Enter, Exit, LogicUpdate and PhysicsUpdate
    StateHandler, unique for every gameObject, where you reference every state you have for this gameObject and define starting state which then goes to FSM that runs the system.
    Any number of states that inherit from State and override it's methods. Those have a reference to StateHandler to be able to trigger state changing.

    and finally

    Script or ScriptableObject for this gameObject data like health, mana etc.

    Maybe it's not the best solution but it's simple and it's working. Thanks all the people in this theme for helping me, much appreciated.
     
    ava_unity565 likes this.
  9. Genovine

    Genovine

    Joined:
    May 25, 2014
    Posts:
    21
    Same here. The FSM checks multiple boxes.
    Well, that's what it looks like to me. Mine's Here :

    https://forum.unity.com/threads/game-state.1261181/

    1. Something to persist through scenes.
    2. Something to listen to player input.
    3. Something that only exists once.
    4. Something that keeps me organized.

    I'm not an experienced programmer and I don't speak computer. But that doesn't mean I lack logical skills or how to frame things. I'll say "I (probably) understand how _____ works" for about anything." But this is mostly due to not understanding the language or where to find a function that could help me.

    Basically, when I look at my state machine. I see the place where player uses the Joystick to press a button. The button activates a function, which changes the state of the game through a series of logic.

    You press "Y" button, which deactivates player controls, then opens the players "inventory", then reactivates players controls. But this time the controls do something different, because your inside the inventory menu. Pressing up and down no longer controls players movement, but scrolls through the inventory.

    At least, that's the way I see it..
     
  10. Zajoman

    Zajoman

    Joined:
    May 31, 2014
    Posts:
    15
    I wholeheartedly agree with everything Kurt has to say about this.

    Start simple, not complex. Even if you were an experienced dev with several published games and AI systems under your belt, I'd still start simple. Just write the simplest, most straightforward code that does exactly what your AI agents need to do.

    That means you have a single class (or bunch of free functions) that implements all the logic. Enums and switches are your friends.

    It even seems you were on the right track here. Why would a few switches be a pain to debug? How can that be any harder to debug than a large, general-purpose FSM made of multiple classes and interfaces and abstractions and whatnot?

    Write very specific code first. Achieve a state where AI agents do exactly what they are supposed to. Then, opportunities for abstracting things will present themselves naturally. Patterns or repetitions will emerge, and it will become easy and obvious to compress them into pieces of reusable code (functions) or even larger systems, if need be. Or they may not; maybe the straightforward code you wrote in the first place is all you need.

    Trying to come up with a generic, abstract framework for something you don't even have a concrete idea about yet is very, very hard. And unnecessary.

    Unfortunately, that's the state of things. I guess practical people who want things done just do them without fanfares. Or they just don't think writing a trivial FSM is anything special to make YouTube videos about. On the other hand, those who blindly subscribe to the OOP academia religion will produce heaps of content, day after day, because hey, even the most trivial problem can be solved in the most grandiose, abstract, encapsulated, independent, super-future-proof way, so then it seems like something worthy of following.
     
    sonmium and Kurt-Dekker like this.