The State Pattern (C# and Unity) - Finite State Machine

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Certainly not the first or the last video to be made on the State Pattern. ;)

I made the video partially to improve my understanding of the pattern and hopefully it's useful to some of you out there.

And yes, I know I need a teleprompter so I can look at the camera while reading. :)

๐Ÿ‘๏ธŽ︎ 3 ๐Ÿ‘ค๏ธŽ︎ u/OneWheelStudio ๐Ÿ“…๏ธŽ︎ Jun 29 2020 ๐Ÿ—ซ︎ replies

Really appreciated this video. I'm currently running with the enum/switch approach and it's getting pretty gnarly and the main reason I never went with the interface approach was because I didn't really understand it. This vid did a great job of breaking it down - thanks!

๐Ÿ‘๏ธŽ︎ 1 ๐Ÿ‘ค๏ธŽ︎ u/elemmons ๐Ÿ“…๏ธŽ︎ Jun 29 2020 ๐Ÿ—ซ︎ replies
Captions
in this video I want to take a look at the programming pattern known as the state pattern this pattern which is particularly useful when dealing with simple to moderately complex systems can be thought of as having different modes or distinct different behaviors but before I get too far into the video I want to give a quick shout-out to my patrons and my youtube channel members thank you for supporting the channel and the videos that I get to make the state pattern definitely has its limitations but like any other pattern in the right situation it can help to detangle code which makes debugging and adding new features or behaviors easier and much less frustrating you'll also hear the term a finite state machine or FSM thrown around and both of these are implementations of the state pattern the asset playmaker is fully based around FSM and bolt has state macros or state graphs that function as finite state machines to help illustrate the state pattern I've created a simple project where an NPC shown as a capsule needs to search the maze to collect yellow cubes and while it's doing that if it sees one of the red spheres it will attack and destroy it so take a minute and think it through maybe even pause the video how would you program that particular behavior now if you're just trying to prototype the behavior or maybe you're just learning to program your first attempt at coding this behavior will likely be with a series of if statements which can work if you make good use of functions and return values you can even make the code pretty clean and pretty tidy for example here's code that I wrote the functions pretty well it uses a few if statements in the update function to control the behavior as a side note I don't really want to go into the details of the functions themselves as I want to focus on the architecture in the structure of how those functions are used if you want take a closer look at the code in the project I'll include a link in the description below now at first glance this code is perfectly fine and that is if this is all your NPC will ever do but the problem with this pattern or style of code becomes apparent as more behaviors are added we all know that feature creep is real and that you will add more behaviors so this is where we bring in the state pattern now the state pattern is not about reducing the number of lines of code in fact you'll likely make your code longer but it rather it's about organizing your code and adding clear delineation to which chunk of code is running there are at least two different ways to use the state pattern that I want to look at the first I think is by far the most common and was certainly the way that I implemented it when I first learned about it the second is far more abstract but in some ways cleaner and somewhat easier to maintain our first method makes use of an enum that has a value for each of the different states or behaviors of the NPC in my example I'll need a wander collect a chase state the base NPC class will then need an instance of an enum in my case I've set the default value to the wander state then in the update function rather than a chain of if statements we can use a switch statement with a case for each of the enum values then in each of the cases we can call the needed function for that behavior already we can start to see the organization forming each state has a clear chunk of code in the switch statement and the NPC can only be in one of those states at any given time which is great but we need a way to transition from one state to another and this is where you may start to see the unraveling or the limitations of the state pattern in each case we need conditionals to determine if the state should change and this brings back some of the ugly if from our earlier implementation if we do need to change the state we can simply change the value of the enum instance and in the next frame the switch statement will evaluate a different state now at first glance this may not appear to be an advantage over where we started but there's a major advantage when we started we needed a way to determine which state we were in picking from all the possible states with this implementation of the state pattern we only need to decide if we need to change States given that we are already in a particular state this greatly simplifies the decision albeit at the cost of a few extra lines of code add to this that in the system is common for a given state to only transition to a limited number of other states for example in my case if I don't want the NPC to stop collecting if it's these red sphere and it should only attack asphere if there's no nearby cube to collect if that's the case the state pattern may actually reduce the amount of code needed as well as serving to untangle the code this implementation of an FSM can be used for all kinds of different behaviors it could be used to control animations background music or even which you buy elements are being displayed at a given time my personal project I use a vaguely similar approach that makes use of static enums and events for game modes so that various managers and UI elements can act or react based on the state of the game the clarity of being in exactly one state has greatly simplified my code and made it far less error-prone so this is all well and good but you may be able to see that the end result of this approach when the number of states gets large is still a complicated mess all the state switching is in this one update function which couldn't quickly get unmanageable and not to mention pretty ugly so we can take the state pattern a step further this step is more abstract still imperfect but it does buy us something in terms of untangling the code and cleaning up the implementation this step is going to take each state and place it into its own class each state can then me and control of itself and will determine when to make a transition and each state will also determine which state to transition to for the next frame the first step is to create a new interface which from my case I'll call inbc state this interface will have one function called do state that will have one input parameter and also a return value this function will be called by the NPC base class to run the state's behavior the input parameter is there so the NPC can pass in a reference to itself so the state can have access to any of the necessary variables on the NPC and finally the return value is used so that the NPC or whatever your code is for will know which state to be in for the next frame and with that done we need to create a new class for each date and those classes need to implement our newly created AI NPC state interface I've moved all the functions and used each state into the corresponding class this can cause some redundancy with functions but I think the overall organization of having each state tucked away into its own class and file are well worth the potential redundancy I've also chosen to leave the variables on the base class itself this allows the base class to be passed into each state which in turn provides access to all the data needed for that state this is done at the cost of making those variables public now each state will need to have its own do state function fully implemented but before we do that let's head back to the base NPC class as this needs to be restructured and its restructuring will help us to understand what needs to be done in each of the do state functions looking at the new base class the impact is pretty dramatic in the reduction of the complexity of the code but at the same time things have gotten far more abstract so let's take a walk through it we can see a variable for the current state this is of the type inbc state so that it can store reference to any of our newly created state classes next there is an instance of each of the states that will be used by the NBC note that I've created a new instance of each state so the values won't be no in the on an able function the current state is set to the wander state to initialize the NPC's starting state then there are wonderfully short update function will call do state on the current state and set the current state to the return value what this means is the current state will do its thing and then determine what state the NPC will be in the next frame if you let that sink in it's pretty darn clever and in some senses the entire update function of the NPC is changed depending on which state is currently running next let's return to the individual states and implement the do state function in the example of the attack State I'll check to make sure that the nav agent is not null and if it is we'll get the nav agent component off the NPC after that it's just a matter of running the attack code and then using similar logic to our earlier FSM implementation to decide which state should be used in the next frame the biggest difference here is that we were returning a state that is already on the NPC and if there is no state change we're returning the same state that is currently running we can add similar functionality to the wander into the collect state and that's pretty much it our abstract but behaviorally simple FSM is complete if we wanted to add an additional state we would need to create a new class add an instance of our class to the base NPC and allow other states to transition to that new state as long as in the Murrah state stays fairly small you name five or ten this is a pretty clean solution so let's talk about the downsides of the state pattern clearly if the system gets too complex it will quickly become hard to work with or maintain in a solution such as a behavior tree will be a better fit also by keeping all the variables for States on the base class this allows that state themselves to stay cleaner but as mentioned earlier it does come at the cost of making the variables public this could be partially resolved by creating an additional class to serve as a data container this sort of just passes the buck but would result in fewer publicly accessible variables on the NBC itself using a data container would also open the doors a bit wider to allow these states to be used or reused by other entities so that an additional wander state for each type of NPC would not need to be created so there you go that's a quick look at the state pattern if you want to learn more there are plenty of other online resources but I'd also encourage you to take a look at the book game programming patterns as it offers a more detailed dive so I hope this has been interesting or better yet useful for you and your project until next time happy game setting and my hands are in the air still it's hard we'll do cult
Info
Channel: One Wheel Studio
Views: 32,622
Rating: undefined out of 5
Keywords: Unity3D, Game Development, Programming Pattern, State Pattern, Finite State Machine, FSM
Id: nnrOhb5UdRc
Channel Id: undefined
Length: 10min 4sec (604 seconds)
Published: Sun Jun 28 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.