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 Classes and FSM Optimisations

Discussion in 'Scripting' started by Freakish, Sep 6, 2023.

  1. Freakish

    Freakish

    Joined:
    Jun 3, 2015
    Posts:
    73
    I often avoid using classes, I came from a C language background (Spaghetti C) was a common occurrence when code became large and complex. But for some reason I never took to C++ and a class based approach.

    Unity and C# offer a fairly good mix of being able to combine the two and that suits me, as I can often get away with not using a class based approach in smaller projects. My current VR project is quite large and complex, but I have managed to use a lot of code reuse via a FSM.

    I have a lot of interactable characters that use the same FSM, somewhere along the line I kind of started using a FSM state like a class. For example I have a 'ProgramState' that I have put most of my functions in, and then in other states like 'NavigationState' or 'EngageState' I will access the functions via something like:

    myState.programState.EngagePlayer(myState);

    This way I avoid a lot of repetitive code and writing it multiple times, but I'm wondering about the advantage/disadvantage to doing this compared to say putting the contents of the ProgramState in a proper class.

    Would there be a memory and performance advantage to redoing my ProgramState as a class.

    I don't know much about the internal workings of C# and how it's allocating the memory etc to all of the functions in my program state, multiplied by dozens of characters using the same script.

    Would there be a noticeable difference in having a few classes for which the FSM would access instead in this case?

    Am I doing it wrong? :)

    Cheers.
     
  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. Freakish

    Freakish

    Joined:
    Jun 3, 2015
    Posts:
    73
    Thanks Kurt, It's basically what I'm doing. The State Machine is rather simple and only has a few states, but I found it it did make life a lot easier in this project, early on I was in a state of "If, Then, Bool" hell initially and the state machine enabled me to avoid that and kind of have a way to exit certain situations cleanly.

    It's been working well for a year, but as a solo dev, I tend to iteratively clean house and try to make small improvements, every few months. Having to do everything from sound, animation, modelling, textures etc, I try to go back over and make small improvements to each bit after getting it working first.

    It is working well, so I will just keep going with it, as is. I was just wondering if I was doing it wrong, or was using excessive memory allocations or something via doing it this way. But it doesn't seem to be causing me issues, so I will continue solving other problems that are... :)

    Cheers!
     
    Kurt-Dekker likes this.
  4. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    839
    Fundamentally the only difference you'd see if you took a 'class based approach' is that instead of treating classes as complex types that you pass to a function you are implicitly doing that because the function is declared as a part of the class and instance of that data is implicitly passed through 'this'.

    At the end of the day C# can be used with a lot of static functions where you pass data into them but it's fundamentally designed as a class-based language. People have been using it like this just fine in large-scale commercial products for decades now. The performance overhead of such things is only ever going to become an issue in the absolute most extreme cases of scale which as a solo dev you are likely not aiming for. And if it did become such as issue you'd probably just use a different technology in the first place.

    As a side note I'm a believer that procedural evangelists and and OOP evangelists are really just arguing over semantics and the underlying strategies they employ are mechanically almost exactly the same thing. Just don't ever tell them that! ;)
     
  5. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    With viewing from "outside the box" in thinking, you could easily make everything you need happen in 1 script. However I strongly recommend against that, as "cutting things up" is more preferred(simplifying things).

    Personally I'm a fan of Inheritance and Static, cutting out any need for interfaces or scriptable objects(potayto/potahto) lol... As it was once described by a smart programmer "Which code works better? the one that does what you need it to"..

    With that being said, it's all on what you understand better, and what feels right. There are multiple ways of doing the same thing. Is one way a bit more of a micro-optimization? Is another way a bit more readable, or understandable when you come back to it months later? Of course..

    Now I will say, making generic functions(to cut down on typing the same thing multiple times) has shown some benchmarking benefits(to me). I'm still foggy on the exact details of why, but found with the case of a 'for loop' within a 'for loop', if the second 'for loop' is it's own function, it winds up being a tad more performant. This may mostly be the case for the benefit of allowing a 'return' to only allow one section stop reading faster, but in the case I tested, this was not the case.

    So until I can find a reason why making separate (generic)functions hurts in some way, I'll stick with my tested benchmarks, and just keep doing what I'm doing..

    But with that being said, always test your own results, so you personally know and can see what is better here or there. As you will find the results are always different per scenario. So stick to what you know, and what makes sense to you, or just plainly makes life easier(as far as typing a lot of the same things).

    For me, having class instances makes the most sense, so each object in my projects each have their own particular class, with of course a parent class that groups them(for generic functions), with more parents leading up to the main communicator. But that's just me. :)