Unity Bots with State Machines - Extensible State Machine / FSM

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up today we're going to talk about something exciting that could completely change the way you do game development or at least augmented and open up a whole world of possibilities for you and that something is the state machine or the state pattern we're gonna dive into the details of how a state machine works we'll talk about the fundamentals but don't worry it's not very complicated we'll talk a little bit about state machines that you already may be using like the animator state machine that's already built into unity and then we'll talk about how to actually build out these states and implement them in a very easy to use and very extendable way so that we can reuse the state machine for game flow state for AI state controlling little bots that run around or even a complete RTS or go all the way down to animation state machines and controlling those in our code so if you're building a game that's got a game flow where you transition between levels or a I like NPCs and BOTS that run around and fight or in our case harvest this video should be perfect for you so just follow along and you should be able to grab the source code down below but don't forget to like and share and subscribe and all that stuff before we get going especially just just share the video you don't even have to like them subscribe anyway let's go so I'm going to show you how to build quite a bit we'll build out an NPC that actually runs around harvests trees returns back that wood and runs away from scary things and you could extend this out to be a full RTS or whatever kind of game you want but you'll be able to have a state machine that you can reuse anywhere and before I dive into the actual fundamentals though of how that works I want to talk about what a state machine actually is and I wanted to use an example that I thought would apply to everybody something that you've probably seen before and that's the Meccan em animation system so what we're looking at here is the state machine for the animator of our footmen this is the thing that controls whether he's in a walking animation and idle animation a run or if he was doing the attack which is the animation that you'll see when he swings his axe at the tree I just reused the attack animation to that so how does this work well we start off with an entry node and this just tells our state machine where to start what the first stage should be so we go from our entry right into this walking node so our default state is walk which just makes the NPC play the walky animation if his speed cops down below point zero one we have a condition on this transition just switch him into idle and then if we go and we're in idle and we go above zero we go back into walk we also have these two transitions from any state and the way that this works is no matter what state or in we can transition into a running state or an attacking state so if we get the flee parameter set then we will switch into running state and we'll just go into a run animation until fleeing is no longer set so we'll look here I stay in that until fleeing is no longer set same with attack when we get the attack trigger or the harvest triggers what I've called it here we'll do an attack which plays that swing and then we don't do the wait so we just go right into idle which is probably gonna move us into walk once we start walking around and you might be thinking oh that's cool animation stuff who cares I'm here for the AI that's the thing I care about and that's where we're gonna go next so we're gonna take these same principles that same state machine the same kind of flow and implement in AI system so that we can control what the NPC is actually doing in the decisions it's making we're gonna do that through a gathering system like I said and we're gonna set up this little NPC to roam around go pick up some trees chop them down for us I guess and then pick them up return them back to our stockpile and keep building that up and then we'll add in a little bit of something for him to be afraid of maybe he can run and get scared and drop all of his wood when a bad guy comes we could alternatively make him start fighting the other guys or even have teams of these guys fighting for resources and battling with each other before we dive into the code let's do a real quick recap of what's in the scene so you know what's there and you're not missing anything we've got a main camera that's using cinema sheen that's why we have this CMD cam and it's following the player around just using the foot man as the follow target in the look target we have a canvas here that's just being used to show the stockpile text that's how much has been returned to the stockpile you've got 8 footmen here it's just a prefab that have duplicated and turned them all off but I've got 8 of them here so I can turn them on and we can watch a whole bunch of them go harvest at once or I can flip them back down to just having the one on we'll go back to the details of this script in just a moment though there's this prefab here we've got a wood dropper script we'll go into that way we've got a stockpile that's this object that we're returning to and it's just using an animation to control how much wood is in there so we've got an animation with each keyframe adding an another pile of wood so we just animate through the percentages and tell us all the way full we have a beast that's that little tiger walking around and he's just using some random points that are set up through some transforms underneath this environment section so he just picks a point in roams around between them to give our enemy or our player something to run from and that's about it now let's jump into the footman because that's where really the core of our logic is in here we've got our animator that's the animator controller that you actually saw earlier that's controlling how he walks or runs or attacks or it goes into an idol but he never really uses the idol he's got a nav mesh agent so you can walk around and we have a nav mesh baked so if you're on your navigation tab make sure that you've baked your navigation mesh and that you've got things like your terrain here where's our terrain somewhere down in an environment I'll just click on it but we want to make sure that our terrain is also set to navigation static under this static checkbox it's a little bit off-screen but if you drag it over you'll see the navigation static option so I've got all of that set up I've got this NPC here ready to walk around what's making him actually walk around and do what he's supposed to do well let's go back to the NPC select him one more time and look at the gatherer script so you've got a sphere Collider by the way that's the trigger volume and that's being used just to detect the tiger coming in all of the work here all of the stuff that we care about all of the AI is gonna be right inside this gatherer script now I'm gonna open it up we're gonna take a real brief look but then we're gonna jump into the state machine fundamentals we're gonna talk about how the state machine works and then we'll jump back to the gatherer and talk about how we're implementing the state machine and using the state machine so first let's take a quick peek at the gatherer so here's our gatherer and it's important to note that this is not the actual state machine this is the thing that uses the state machine if you look at line 11 you'll see that we actually have a reference to a state machine and our gatherer could also be like an enemy or a tank or something else it's just the object or the thing that's using a state machine this could be all the way down to the NPC level or it could be like a game state control that has the state machine in it in our case though we're doing an NPC the gathers so it's in a gatherer script and then you'll see that we do a lot of setup in awake I'm gonna expand it briefly look at it and then we're gonna dive into the state machine so here you'll see that we do what looks like it seems like maybe a lot might seem overwhelming like what is all of this stuff but as we go through this it's gonna make a lot of sense and it's gonna get really really simple to read and it's gonna get extremely easy to understand and build upon so if this looks overwhelming don't worry this is literally the most complicated part and it's really just three things that we're doing multiple times with a lot of text so let's dive into the actual state machine let's go up to line 11 I'm going to hit f12 and just go into the definition of the state machine so here's our entire state machine class you can see that it's only about 90 lines long and it gets a lot of work done we've only got four public methods here we have a tick we have a set state and add transition and an add any transition we also have incited a private class that we're only going to reuse inside the state machine called a transition and a private method to get a transition we up at the top have a current state that uses this I state interface we'll talk about that in just a moment we've got a dictionary of transitions so it looks like we have the type as the key and a list of transitions named transitions we have current transitions any transitions and empty transitions so a whole lot of transition stuff in here in fact if you look for of our five lines up here are all about transitions and that's really important because the state machine is all about the transitions if we just had a single state and it never changed States well we wouldn't need a state machine we just need an update loop right the transitions are what make the state machine work that's how everything ties together and that's where all of the power comes from well start with the tick method because this is our primary interface into the state machine in fact it's the only method that we call outside of our setup or initialization time and you'll see that we call it from our update in the gatherer so the gathers update method is a single call to state machine tick our tick method does not very much it looks for a transition calling get transition if it it's a transition back on line 32 we set the state to the transitions destination or the two state on it and then on line 34 we tell our current state tick if we look again our current state implements this ice data interface and I want to go take a quick peek at that Before we jump into setting up our transitions so our I state interface has a tick and on enter and a non exit and you can even notice that we only have one usage of each of these because we only ever call them from that single state machine but we do have six implementations because I've created six states in this project let's go back to our state machine now and take a look at the set state method and see how this works the first thing that we do on line 39 is check to see that the state that was passed in is not our current state if it is then we just bail out because we don't want to set our self to the current state over and over then we check to see if we already had a previous state and if we did we call the on exit on it so we can do its cleanup like turning off an animation turning off a nav mesh agent something like that then we set our current state to this state that was passed in so that when we tick later we'll be ticking against that current state and then eventually we call on enter on line 49 right here on line 45 and 46 and 47 though we do a little bit of transition setup so let's talk about transitions in the next part right here because that's our next method add transition and if we look at add transition you'll see that it takes a from a two and a function bool predicate so this means that we need a function that we can give this that's going to tell us when we need to actually do the transition let's see how that works expand out out add transition and the first thing that we have here is this transitions try get value and I want to talk about this because I find it a little bit confusing for people who don't use dictionaries regularly like I do so let's go to definition on it real quick I hit f12 and here you'll see that we have a dictionary of a type as the key so we look them up a by type so this will be our class type and this is going to be class types like the flee state or the search for resources they so it's going to be the type of flee or type of search for a resource or type of harvest or something like that that's gonna be our key here is just that type and you can do get type on any object to return back the type of the thing if you need it the second thing in our dictionary or the value is going to be a list of transitions so for every source state or every source type or source I guess its state type we have a list of possible transitions so this is just basically a storage mechanism for all of those lines that were connecting the different states in our visual editor it's there the type is the source node and then the list of transitions is all of the lines or exits that it can go on and then these transitions are of course going to have conditions on them so let's dive back into the add transition a little bit more so the first thing that we do is try to get back the list of transitions for that state if we don't already have a list of transitions for that from state which we're getting--we're using from get type which gives us back that type then we create a new list and we add that in to our dictionary so we say transitions of this type equals this list and this is the same as calling dot had and giving it a key and a value if we can also just set it like this so if you're used to using dot add that's Office's the next thing that we do is say transitions dot add and we add the transition so here we've got the list of transitions for our specific state and we're just adding this new transition to it and in our transitions we have a two and a predicate so let's go look at that now and you might notice that this is a class but this is actually a class inside of our state machine our state machine is so tight and compact that we have another little class in it and it's still under a hundred lines so let's expand out the transition class here and here you'll see that we have a public function that is a condition so it returns back a bool and you're gonna see how to implement this in a while if you're not used to using func Abul don't worry it's gonna be really easy and obvious when you see it the actual implementation and then we have a nice state of named two which is the state that we're gonna transition to so this is really just a simple data structure it has a condition in a two and a constructor that's it there's nothing else to it no magic in there at all so when we add it we're creating one and we're just putting it into this list Oh the next thing that we have is add any transition and here it's even simpler we add to our any transitions list and if we go back up f12 this is just a list of transitions so what we're actually doing here and it's kind of important to note and let's add some space here is we're saving off all of our transitions in this dictionary here and then we're switching out which transitions are active or current based on our state so when we set our state this little bit of magic that I said I would get back to later all it's really doing isn't saying hey dictionary give me the list of transitions for this type and shove it into current transitions if we don't find anything there was nothing there then just give me the empty list so I can still iterate without having to worry about it and which we use this empty list appointment back to that empty list and we're good the main reason we were doing this here is that we don't want to allocate any extra memory here since we're doing these state transitions relatively fast and often and it could be times thousands or tens of thousands of things we don't want to be creating new lists and changing stuff we want to make it as simple as possible to iterate through these and do is you lookups as possible but also as fast so lookups as possible okay the last thing that we have in this class and this is I guess the end of it or where the real magic happens and I guess it's these last twelve lines is the get transition and this is simple it's really just saying hey first loop through all of the any transitions and again the any transitions it might make more sense here are the transitions coming from any state because they don't have a from stage so we're never switching out the any transitions they always exist so we loop through them we check to see if the condition returns true if it does then we return back hey this is the transition that's valid now the ordering of them is all gonna be based around what order we put them and of course we could add a priority system if we wanted to but I've never felt the need for it I can just put them in the order that I want once we're done with the any transition so if we didn't find any maybe we didn't have any any transitions or which didn't meet the condition for him like we didn't run into a lion and get scared then we go through our current transition so this will be the transitions for our current state we checked the conditions if we meet any of them then we return back that transition otherwise we return null and let's go back to where this is called so do shift f12 and here we remember if we return back null so we don't find a transition then we just tick we don't do anything we only set the state if we got a non null state and then either way once we're done we call the tick of our current state which does the actual work for our game so let's go see what our states actually look like and how we use this state machine to build a system that actually plays and does something logical so I'm going to go back to our gatherer and take a peek at our awake there are a couple things that we're doing here the first is in the beginning of our awake we cached a couple components we get our nav mesh agent our animator this enemy detector script which let's take a real quick peek it's really just a trigger detection we check to see if a beast has come in range and then we check to see if a beast has left range we set a little flag for whether or not a beast is in range does not handle multiple beasts or anything like that but it's a nice simple little component to give a good example then we have a particle system that we're getting and putting that into this flee particle system just so I could show a little bit of particles and a little bit of more fun stuff the next thing and the biggest part I think the most important part is line 25 where we actually instantiate our state machine so our state machine is just a private field up here and we instantiate it in our awake next we're creating our state's so Lions 27 through 32 are all of the different states that this gatherer NPC could be in he can be in a search for a resource state he could be any move to selected resource state a harvest return to stockpile place resources and stockpile or this new one that I've added a flee state so the search state let's talk about that real quick in fact let's go through each of these step by step and then we'll talk about the transitions between them our search state takes a single parameter in the constructor for this it's going to take in the gatherer because we need some reference to something on this NPC and if we look at our search for resource go in here f12 we can see that we're cashing this gatherer and the thing that we need on it actually appears to be the target so we're setting a target on our gather and down here you see that we're also referencing the transform so the way that the states are generally set up is that they implement high state and there other than that just a plain old class they're not a monobehaviour that are not a component or anything like that it's just a public class that implements this high state interface the ice data interface again has that tick it has our on enter and on exit and if you look here on in turn on exit don't do anything for this state our search for resource state doesn't need to do anything fraud in tour so they just have empty empty implementations of these and I'm totally okay with that I know some people like to have a separate interface for each of these different different possible calls here but I think that at the state level I expect that most of them are going to implement at least one but often two and sometimes three of these and I don't want to mix and match them I think that having just a simple ice day it works for that so we've got our tick method that's where all of the works being done but I also want to point out that our constructors can vary because these are not mono behaviors we can have constructors that take in any number of parameters and this is usually where we'll pass in the data that the state needs to act on so if the state needs to work on the gatherer it whoops give it the gatherer as a parameter in the constructor here then we cache it and then in our tick or to say the target is look at that choose one of the nearest resources out of five so I have a pic from nearest here and we're passing in five so we just pick one of the five nearest things and here we're doing it in an extremely uneme I want to point that out we're just using a link query that orders them by distance checks to see if they're depleted and then takes five and then randomizes them so the selection here is extremely unoptimized but we only do it when we don't have a target and it's not a thing that I care about optimizing right now a simple link statement makes it a lot easier for me to understand what's going on here so that's our entire state every tick we choose the nearest target and that's it you might think like hey is I mean we're just choosing a target every frame no because what's happening if we go back into our gatherer is once we found a target we're going to go into this and move to selected state and you see that here this app search move to selective when it has no target you see that what what's actually happening there is that's where we're setting up our transition but let's look at move to select it before we dive into the transitions move to selected takes in this the gatherer as the first parameter but it also takes the nav mesh agent and the animator and you might be wondering why why not just pass in the gatherer and then have the state know about know how to get the nav mesh agent know how to get the animator and the main reason is that I want my states to be as dumb as possible and as reusable as possible I don't want them to have any extra info that they don't necessarily meet in fact they don't particularly like passing in the entire gatherer object but for this example it made it a little bit easier to do so we'll dive in here into our move selected or move to selected and here you see that we just again cache together the agent in the animator nothing special there and then in our on enter we're actually doing something special so I want to zoom in here and take a peek at it there are a couple things that we're doing first is we're setting this little time stock variable this is just a kind of a safety check in here to see if the thing hasn't moved in a while then maybe we need to pick a new target so we're just resetting this this little stuck timer the other thing that we're doing and the more important part is setting our nav mesh agent and able to true so when we enter a movement state we want to turn on the nav mesh agent and if you look down here and on exit we're actually turning it off when we leave then we set our destination to the target which was set up before it's transform position so in the previous state we found a target we set that on the gatherer in this one we're using that target and we're using its position and then we set our animators speed and again on exit you see that we set our speed back down to zero so here we have nice simple control over our nav mesh agents state in our animator state without having to worry about things getting a little bit confusing and messing because we're only ever in one state at a time we don't have anything else swapping our nav mesh agent or changing these settings so we don't have to worry about getting into some weird state that doesn't make sense okay let's go back again and if we get back to our gatherer I want to take a peek at the ad transition now so we've got these other states and we'll take a look at those in just a moment but I want to look at the transition between search and move to selected so we are calling this method it says at which is actually just a shortcut it's a shortcut for this function right here and I want to show this because it's a neat little trick but it's a thing that can really catch people off-guard so what we're actually doing here is creating a method inside of our method or a function inside of our method that we can reuse so I have this void a T which is just short for add transition which takes a to from and a func of bull named condition and here I've just made it an expression body method so I could also just do something like this just just to show it real quick I could do it like that it's just a method that's calling state machine add transition so we're essentially just getting this little shorthand and if I undo you can see this is what it looks like so here we're really just calling add transition of search move to selected and the condition is has no target which is also another one of these little functions here so we've got another expression body method here that's inside our function it says has no target and it just returns back whether or not the target is not know and as I read this again I realize that the method name here is actually wrong this should say has target so we'll actually rename this right now so we want to check that if we have a target we want to move to selected not when we have no target oh it's silly okay so we've got the transition here and again the way that it's working as we go through we check to see if the transition is valid by checking the condition that was passed in in that condition that was passed in is that it has a target so we're actually going to do this check here to see if we have a target every frame when we're in the search State and once we have a target then we'll return back true and we'll do that transition so we'll go from search to move to selected and realistically this is all happening in one frame because we're gonna find it well it's in two frames really we're gonna find it in the first frame and then the second frame the transition will be valid so we won't kick our search again we'll take the move to selected will enter and move selected and then ticket so what do we do after that well we have another transition from move to selected back to search if we get stuck for over a second so our stuck for over a second is check just checks to see if this move to selected dot time stuck remember that was the variable that I told you we were resetting down here and on enter we're actually incrementing it in tick if we haven't moved so if our position has stayed the same in the last frame we'll just keep incrementing it that's the amount of time that we haven't moved just stayed stuck so if we're stuck for over a second then we'll do the transition back to search and find a new target otherwise we also have a transition here from move to select it to harvest once we've reached our resource so if our reach resource check is true what we means that we don't or we have a target and we are within whatever this distance is so we have a vector3 distance check it looks like less than one meter so here it's a little bit long and a little bit in the line I would generally split this up and make it a little bit easier to read but you get the idea that we can put in these little properties or these little functions here to simplify our code and make it a lot easier to read what these transitions are doing what they're trying to figure out especially when we rename them and make them named right so the next transition that we have from harvest to search is just checking to see if the target is depleted and I have room for more so we'll check to see that we have a target the target is not depleted and depleted just means that we've gathered all of the resources from it and then we'll check to see that we're not full on inventory either and inventory full is just to check to see that our gathered amount is greater than or equal to our max carried so we can either search for a new target if we run out if our target is empty and we have room or if our target is empty really and our inventory gets full at all then we will switch over to return to stockpile so we don't even care about our target we just wait until our inventory fills up and then we'll return to stockpile return to stockpile just does the same kind of thing it moves you towards the stockpile until you've reached the stockpile which is checks to see that we have a stockpile in that distance is again probably what under one meter yep under one meter it's less than a meter away and then we call reached or reach stockpile is true so we'll switch to place resources in stockpile and then we'll switch out of that once our gathered is back to zero and notice here I didn't put a property here or a method just to show that you don't necessarily have to do it you just write the lambda right in there it's just that I find it easier to understand and read and go through the flow at a faster speed if I put in these little functions here to just make it very obvious and human readable what it is you're trying to do there so let's take a look at some of these other states well you know before we do that let's look at the last thing that happens in here the last thing that we do because I remember all of these are just functions these are not actually part of the code so the last thing that we do in this method is set our state to search so we set that default state and remember that's when I said that we were only setting the state from one spot outside of here or outside of our tick and this is that one spot so we set our initial state okay let's go take a look at what these other states do and see how it all ties together and works so we have the search and the move to selected which we've already gone through and then shoes nav mesh agent setting the destination to go to them then we have the harvest resource State harvest resource takes a gatherer and an animator because we want to play in a tacky animation when we animate fact let's zoom in a little bit and then in our tick we check to see if we have a target so if we have a valid target and we have met our time for when we should pick the next one then we will call gatherer take from target and we'll set the trigger on our animator this take next resource time is just our current time plus one divided by the number of resources per second so the goal here so that we can set a resources per second rate which I believe I've just hard-coded at three now but we could obviously pull this off of the gatherer or some other settings or even calculate it at run time if we needed to but we figure out the rate and then we just allow them to take and a resource each time they take from resources just calls take from target which if we expand out doesn't do much it calls target take which just takes a single resource from it it increments are gathered and updates or invokes the on gathered changed event so that our UI elements will update and we take a peek at those in just a moment too but first let's go into target I take this target take also does a couple things and if you're gonna implement this thing you might want to understand how it all works so target that take reduces the availability count assuming that we have some left so if we're out of resources we return false otherwise we reduce it by one and then we update the size which is really just the game object scale Oh mr. tab here so you see that all we do here is lerp between 1 and 0 for the scale of the object so when it's full it's a giant tree when it's empty it's an empty tree when it gets down to 0 it disappears and sets in itself the inactive well we also have a snap method to just snap it down to the navmesh there okay let's jump back to the gatherer and look at the last of the states so we know how to take resources we know how to move to them we need to return them to the stockpile so return to stockpile is next turn to stockpile just takes in the gatherer in the nav mesh agent again in the animator because it needs to deal with navigation and animation on enter we choose a stockpile and right now I'm just finding the only stockpile in the scene we could obviously expand this out quite a bit more we enable the nav mesh agent because this is an state that needs to move we set the destination to that stockpile and then we set the speed to animate and then a non exit we just turn it back off and turn it back off again again nothing really special right it's just moving to a destination so you can start to see how these states can be very simple and just do one little thing and then kind of tie together like this next we have place resources in stockpile doesn't do much it says gather dot take and then so it takes a resource from the gatherer every tick and then adds it to the stockpile that's why you see that quick little of the numbers they kind of do that little transition there so every tick we just do one and then that last transition remember when we get to zero we're gonna go back to search so we're just making a transition back to search but then we have this one extra little one that flea and you probably saw this in the beginning but what actually have here is we have this enemy detector and in our transition here that I've added right up at the top we check to see if there's an enemy in range and if there is an enemy in range we transition to the state in fact we don't do it from here though we do it right here it's line 42 now this add any transition and one of the main reasons I added this was that I wanted to show how we use in any transition and what a case for an any transition would be it's usually the type of thing that interrupts the normal behavior of the normal flow something has happened outside and needs to make this thing act in a way that it normally wouldn't and that's what we have here so this any transition gets added and it just checks again to see if we've got an enemy inside our trigger volume if we don't then we bail out and we leave this stage but we don't clear it out until three seconds later just so that we don't get that weird state of like going into fleeing leave and fleeing going into fleeing leave and fleeing as they kind of edge on that trigger so we just didn't make them run for three seconds after they've left the trigger so run away for a minimum of three seconds and let's take a look at that flees state because it's actually the most complicated of the states that I have so our flee state takes in a lot of parameters we've got a gatherer a nav mesh agent an enemy detector an animator and a particle system and then in our on enter we turn on our nav mesh agent because we want to run away consume this in a little bit we tell our gatherer to drop all resources and I want to look at that real quick our gatherer drop all resources actually just tells this would drop or object which is really just a spawner of a prefab to go drop a gather above resource that looks like would even f12 into it you see that it just instantiate it and sets the amount of gathering boss so we're using the same script it's on the trees just drop it on to a little bundle of wood and spawn the wood so they drop the wood on the ground play a particle and run away other than that they've changed or they call the on gathered change so that the event updates the UI and then we go into animator we set the bool for flea hash to true which is just setting our fleeing animation she's an English string to hash for optimization it's a little writer optimization it always recommends we set the initial speed to our current nav mesh speed because I want to cache it because we have a special flee speed so we set our nav mesh speed to that flee speed and this is another example of caching the state of things so that we don't change state when we go in and out of state so if we have to modify something a lot of the time it's good to clean that up on exit and you'll see that in our on exit where is that right down here we actually set our speed back to the initial speed when we leave this one and we turn the nav mesh agent off and turn that flea hash back off but what else do we do when we enter oh we set our fleet speed Oh it we play our particle system in our tick for fleeing we check to see if we're within 1 meter of our randomly chosen destination if we are we choose another random point and then we set that as our destination so we just keep picking random points that are what about 10 meters away or whatever our fleet distance away is 5 meters away so we pick random points about 5 meters I guess not even really random it's some position 5 meters away from the enemy directly away so you just try to pick a point 5 meters away and run to that and you just keep doing that I don't know why I thought it was random guess it didn't need randomization and that's the entire free state code so that's again an a big extra bit of functionality that I've added on without having to write a lot of code without having to go in and change things I didn't have to worry about things breaking when I added a flee state I was able to just drop this in really easily make it do exactly what I wanted and not have to worry about like oh what if it's picking up trees and an enemy comes by or what if I'm playing this animation and we come fired this thing the benefit of this state machine and these discrete states is that everything is contained and much easier to manage you don't worry about multiple things screwing up and messing with state because there's only one state ticking there's only one thing updating the state of this entity of the time now before I wrap this up I did want to show a bunch of NPCs walking around and harvesting so here we go we've got a bunch of guys just kind of roaming around the scene and picking up different resources and getting terrified by a tiger there they go get them all take off and I also wanted to show how that UI element is updating over their heads some people might be a little bit curious about that so underneath each footman I've got a canvas that's set to a world space UI I've got the mode set to world space and then I've got a text component and underneath that or on it I have a gathered text script which simply registers for the on gathered changed here so it registers for that event listens for it and whenever that event is fired off it says text dot set text to the counter parameter that's getting passed in there and then in a way qui cache the text that's it that's how the text works I just want to make sure that everybody saw that and understood how that works in case you're trying to get it to work yourself other than that I don't know that there's much more to show animators can use state machines gamestate can use state machines AI can use state machines it can be at the entire team level all the way down to the NPC level we can even have state machines for specific body parts especially when it comes to a big boss a lot of the time a state machine per body part makes sense so I want you to just think about where state machines might make sense in your game and where you can simplify things by just controlling the state and controlling the flow a little bit better I personally love using them for just general game state and AI but there are a lot of other implementations and a lot of other uses out there there are also a lot of other ways to build state machines you can build them with abstract classes you can have them use enums or strings as keys you can do all kinds of different things this is just the simplest implementation that I've come across in my own experience and the one that I prefer to use a lot of the time because it's very uh opinionated it's very easy to swap into any system and it's really easy to just kind of build on and extend without having to add a lot or go in and change things I can just reuse it across projects so I hope this was helpful for you if you're interested in more state machine stuff or just more AI related things drop a comment down below and definitely let me know also if you're really into state machines and stuff make sure you check out my courses we dive into this stuff and a whole lot more writing them from scratch and going quite a bit deeper into different types of state machines and a lot of other stuff and I also wanted to say special thanks to everybody on patreon and just on YouTube in general because are awesome and being able to put up content on YouTube and teach people how to make memes and how to do cool stuff in unity is a blast so I really appreciate it and I just wanted to say thanks to all you guys anyway thanks again and goodbye you
Info
Channel: Jason Weimann
Views: 64,595
Rating: undefined out of 5
Keywords: finite state machine, unity 3d, unity finite state machine, unity state machine tutorial, unity fsm, unity state machine, state machine, brackeys, gamedev, bots, rts, state machine behavior, state pattern, unity fsm tutorial, unity ai, unity ai tutorial, state machine unity, unity, unity3d, game dev, game programming patterns, finite state machine example, jason weimann state machine, unity tutorial, unity3d college, unity machine learning, enemy ai, jason weimann, patrol ai
Id: V75hgcsCGOM
Channel Id: undefined
Length: 37min 44sec (2264 seconds)
Published: Sun Apr 26 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.