As a newbie to Godot and game design but not to coding in general, the exploration of using a node based approach to state machines was fairly eye opening. Thanks!
This is a great explanation and breakdown of state machines. State machines are one of those things that beginner game programmers should learn as soon as possible.
Of all the YT videos out there on state machines this one is the most straightforward and easy to understand. The idea of each state as a “hot-swappable” brain made it really click for me. Thank you for making this and looking forward to the next video!
Very concise. As a beginner to Godot I understood what State Machines were, just didn't understand all the code. This video has certainly helped me out; although, I did have to watch it a few times to get it down. Very well done!
Thanks for sharing your info with us. I had an old game where the character has several states (run, slide to a stop, turn around, crouch, jump, climb up, climb down, use action) and the code was growing untenable. I've been wanting to go back and add to the game, but the state controller is over a hundred lines and so messy. I'm converting it to your style of node base states and it's so clean. I appreciate it. And your website version of the explanations is an awesome addition. I'm sure I'm dozens of web clicks on it. Thank you!
Thanks for including the Enum + Match statement approach for making simple state machines. I exclusively use this approach for minions/enemies as its less resource hogging compared to the State Pattern approach. The node based State pattern approach is fine to use for Player character and Enemy Bosses.
Thanks! I had a similar implementation except I was using the processing of each of the individual nodes, I think I ran into some overlap where some states were still running while the new states were active. Your way of using the parent's processing sorted this out. Thanks :)
As for giving the state machine a reference to the parent, you can use the state machine’s `owner` property; that will always be initialized to the scene root: in this case, the player. Even if the hierarchy changes, whether when you restructure the Player scene or later during runtime, a node’s `owner` won’t change unless you change it manually using `Node.set_owner()` in code.
Great video! Most of the time, I use almost exactly this approach. The only difference I have is that my separate states fire signals that allow the owner of the state machine to decide what its next state will be based on the owners properties or configurations. By not having separate states reference other states it means that all combinations of states can be used, since the owner of the state machine controls what happens next based on individual state signals. Sometimes these states even have their own 3D nodes in order to determine if it sees a target using a raycast for example. Child nodes of separate states can be interchanged per scenario, thus making it customizable per instance of that single state.
Finally a basic explanation of fsm that i can understand. TBH, i never fully understand state machine even after watching many tutorial and sample project. You just make it all make sense. Turn up, i already using some kind of state machine in my project.. albeit primitive one 😆
Thanks, really needed help with this. Planning on making a platformer game and this really helps achieve that, straight to the point and easily explained. You've got a sub from me, looking forward to more State machine Tutorials for Godot 4
Damn it’s kinda funny seeing this after I bumbled my way through dealing with a character that could swap abilities based upon powerups in game in my own project. I used messy if statements to get it working but this makes much more sense.
ahh, a great recreation of your classic videos. this is the state machine foundation i've been using in godot ever since your original videos. i'm EXTREMELY excited for the next video on (unless i misunderstood) what to do if you need a more complex state machine! perhaps one with a ton of different states...??
Great explanation. I have a game here with a player built using node composition. I believe my next step would be to extract those node that handles jump, movement and so on to their own state. I'll try to do it without copying exactly what you did, but I could grasp the general idea: 1 state manager has many states, which extends the base state node. The state manager will handle the logic between states, while the states has logic for handling input, animation and gravity as it seems fit
I've been using the node-based approach for a while now, but using a generic state script + lambda functions and overwriting them in the state-machine script as needed.
This is a pattern I utilize greatly, and always advise beginners learn to use. My current opinion on the best implementation for node-based state machines is a single node that behaves both as a state and a machine, which allows for hierarchical state machines, although it can lead to some mess if structured improperly.
This is the best state machine explanation around, yet i still cant wrap my mind around it sommehow. Maybe its the language barrier that sometimes gets to me. But awesome vide as always love your content!
Great general overview. Really easy to follow and implement. That said, i do have some issues with using it when i want to react to other signals. In my case, its for character attacks that can combo. I want to trigger a knockback effect on each hit, so i have a knockback state with special behavior, and then each state listens on a signal that the hurtbox has been entered, and transitions to the knockback state. What happens is my signal in the Idle triggers, and transitions to the knockback state, where the signal for the knockback state triggers and applies its effect again. This somehow happens even when i check if the state is active in the signal...
You really make hight quality videos! Thanks alot for all of them! I wonder if you'll ever make a video of an implementation of utility ai in godot 4. Would really love that!
IMO, using Nodes for states falls down hard for larger projects. We use Resources for states instead, with a StateMachine node holding an Array of them. States can be dropped into the statemachine's inspector. The states have initialize, enter/exit state methods and a process method that's called by the StateMachine node every frame for the current state.Much cleaner than a huge list of nodes in the scene to enable/disable all the time. ANd Resources don't need all the extra internal bulk of Nodes. IMO, using nodes is just asking for a maintenance nightmare as soon as the project grows a bit. And I don't even think Nodes is simpler for new devs. But hey! They are a thousand ways to do everything. Just my thoughts. Peace.
My implementation is very similar except I don't like specifying the player type for the parent as this ties to the state machine code to only work for the player class. Instead, I used CharacterBody3D since I am creating a 3D game. This means enemies could potentially use the same scripts but the down side is not having code completion for player specific variables. I guess you could cast the parent to a Player type within the individual states but I am still working that bit out. Good video.
Funnily enough, my implementation of a state machine is more or less the same. Except, that for some reason, I decided to switch between states based on strings, rather than exporting them as variables as needed for each state. In hindsight, I really don't know why I came up with this idea myself! :D Oh, and I also did decide to change states manually, rather than as a return value of a function.
The Godot state chart addon is good and handles a lot of this for you, but lacks some of the flexibly of writing your own. I've used it in a couple of projects and really like it so far. It's worth checking out.
Thanks for explaining things. Question I have is what if your "idle" state needs to access another node inside the character scene. Like to get a particle system and enable it. Its okay to use a reference to that from the "Idle" class? Seems weird because you are referencing up the hierarchy instead of down.
Sure, it is what is is sometimes. I'd probably @export that reference, but you could also pass it in like you do the player if you'll need it a lot of places.
That's the default information that is provided about an input. To hook into input events, you have to at least accept it in your "_unhandled_input" function, but I pass it to the states in case I want to read that information. See: docs.godotengine.org/en/stable/tutorials/inputs/input_examples.html#input-events
I'll touch on this more in the next video, but there's nothing wrong with multiple state machines if you have independent states to manage, such as for a run and gun type of game.
I think this was a really good explanation on state machines. The only real criticism I have is that its really hard to follow the Node approach, even with the source files, for the sake of implementing in a project. The actual states themselves are fine, but there's no mention of how to use the state changes / where to manage the state changes & how. Nvm the code does a pretty good job at it, i just suck
I'm working on a 3D game and I like your approach. I got one question though - do you think it is reasonable to have two state machines for 3D? Because I want to have legs animated when running, but you also can hold item which changes how the arm bones behave and I'm not sure if this is the correct approach, i.e. one state machine for legs and the other for upper body.
I'm going to watch your other video on state machines next to figure this out, but I'd like to raise a question. What is and isn't a state in a state machine? As far as animation handling goes, this system is flawless. Each state has a distinct animation and that part is easy to get for me. But for movement handling, jump and fall control the opposite ends of y-direction movement, while move controls both directions of x, and idle is responsible for the lack of either. Since platformers tend to have x-direction capabilities in air, three of the four states can control when the player moves left or right. I think the concept of states being both directly responsible for movement (jumping velocity is instant once entering the state) and indirectly able to be controlled based on input without switching states is tripping me up. Outside of these four main actions, I'm confused on what actions should and shouldn't have separate states. Overall the idea of "swapping brains" with states is clear and concise, I may just be thinking about this too rigidly.
Rather than breaking it down into movement or not, I like to think of it as "Is this something that would require conditional logic to process?" I might need to do X if I'm falling or Y if I'm not, for instance. The next video should help clarify how to build out functionality and reuse some code to help with some of what you're talking about, but I think you've also actually stumbled upon a common criticism of state machines without even realizing it: they can get complicated pretty quickly.
It is indeed just preference, but I do recommend it once you're comfortable with general coding. It makes it clearer to future you and others what your code is doing, it makes the code completion hints in Godot more helpful, and there are some small performance improvements from using it. Plus, in the case of this channel, it gives a better idea of what I'm doing without having to explicitly call out every variable. Again, though, totally optional and not something you have to worry about right away.
when I try to run this scripts I get an error that reads "invalid call. nonexistent function `enter` in base `Nil`" in the state_machine node, func change_state final line `current_state.enter()`
Do you go through doing this in the video? I'm trying to assign the starting state in my state machine but none of my nodes are able to be assigned@@TheShaggyDev
@@Chase_Is Are your states inheriting from the State class? The export should be typed to State, so will only accept nodes that inherit from State. Can take a look at the sample project if you want to see how everything should be set up.
I have everything that you have in the file in your description. All of my states all extend the State class. So idle is the same as what you have in your sample@@TheShaggyDev
Oh I fixed it. All of my States were extending state except for the actual State script. Thank you so much for the reply, your videos are so helpful!!@@TheShaggyDev
So this may be a dumb question, but I'm trying to learn this while doing a state machine on a simple racing game, but I'm getting my wires crossed somewhere. On the state machine, I need to be able to control the vehiclebody3D, which is of course its parent. But the VehicleBody3D controls things like steering and throttle. The state machine doesn't seem to be able to access those functions (Or exported variables), even when trying to access the parent (Or parent of the parent, to be fair, as the actual states are another layer below the state machine). Any idea how to have the states "latch on" to those functions so they can be modified? Or am I aiming for something fundamentally flawed?
Hmm, I'm afraid I'm not aware of any reason why you couldn't use this technique on the vehicle. Though I'm not overly familiar with the VehicleBody3D node, I don't think there's any specific reason why it wouldn't work.
If you embed a separate 'state machine' and define local 'states' for each type of object 'node', how do you know if you're getting the main supposed benefit of 'state machines' in that you're handling all possible states (and combinations of states...) in a deterministic way? What if not every piece of data in your game is trivially synchronous? What if you have a non-trivial amount of nodes, and in aggregate, they may not complete their state updates within 16ms? What if you have a non-trivial game that has at least one behavior, data or operation than affects a 'state' that could take more than one frame to calculate?
The states are still organized on that object, but there's no need that every object needs to run through one large state machine that keeps everyone in sync. They can, and will, change states at different times depending on the interactions each object has with the world. These small per-object state machines have a minimal impact on performance, which will be a game dependent detail anyways. If the state's can't update in time, profile and adjust where needed. While a lot of common state machine uses in games should be able to run synchronously just fine, long running or asynchronous tasks won't impact the implementation that significantly, nor will that make the state non-deterministic. We still got to this long running task based on some set of inputs to the machine. Depending on the exact use case, a processing state for that object might help to make it clearer what's going on and help prevent invalid state changes while it's processing everything, but that can, again, vary based on the game.
I think you could remove the player related variables from the base State class in a way it becomes generic and reusable in objects that are not players
Either way is acceptable in Godot! I personally tend to put it first as that mirrors other programming languages where you typically have the pattern of "X is a subclass of Y"
is there a reason why you are not simply making the animations and state machine variables on your player node exported vars? on one hand you say that not passing the reference would break the code if you change the node structure but on the other hand you hard code the path to your state machine. just trying to understand your reasoning as i‘m currently in the process of switching from unity where i heavily used inspector set paths
You could certainly do that as well*, but I'm ok with the parent knowing its children. It's the child knowing its parent I'm more cautious of. * There was an issue in Godot for a bit where a top-level exported variable would point to the wrong node when multiple instances were in a scene, but I believe that's been fixed now.
I don't fully understand. Can someone tell me, what in that code (of the node based approach) causes the code to know, which State is inactive? With match, I get, why only one gets selected. But when I "return jump_state" for example... How does it know, that idle_state is no longer active and should not be executed anymore?
The trick is in the code for the State Machine node. When a state returns a new state, that triggers "change_state()" in the state machine, which changes which node is marked as the current state. As the machine only allows for one state to be active at a time, only the current state is ever processed and given inputs from the parent.
how do you make it auto-complete in the states? i'm using my own component "move_component" witch is a class "MovementComponent" I'm passing it to the state_machine and to idividual states aswell but when I use it inside the a idividual state is dosen't auto-complete when I'm writing a function, it works, but I need to keep bouncing to the component script to get the functions...
As long as you type your variable (ie "move_component: MovementComponent") it should autocomplete for you, though sometimes Godot can get a bit confused on types...
Hey so there arent any errors in the code itself, but when trying to run the game it gives me the error (Invalid set index 'parent' (on base: 'Node') with value of type 'CharacterBody2D(Player)'). Not sure how to fix this and any help would be greatly appreciated. (Also i've been mixing and mashing tutorials together so maybe that could be an issue)
I thought I was crazy at first but they did tweak state machines quite a bit. I get whiplash from all of these changes sometimes. Open source engine problems, I suppose.
I'm utilizing C#, and working through this tutorial and a conversion process from GDScript. What would be the equivalent of this section of the Statemachine code: func init(parent: Player) -> void: for child in get_children(): child.parent = parent in C#?
Whats the difference between state.gd and state_machine.gd, the former doesn't have any owner of a node while the latter has whichs state_machine.tscn?
In short, state.gd handles the state-dependent logic where state_machine.gd handles coordination between states. So you might make a run state using state.gd, but let state_machine.gd handle transitions between states, dependency injection, etc.
how do I create a State class that godot will allow my state scripts to inherit? Because right now I get "Invalid inhereted parent name or path." whenever I create a script for my classes that tries to extend my State class. I am at my wits end with this.
There are two ways to inherit from a class in GDScript. The easiest is to make sure that you have "class_name State" (or whatever the class name is) at the top of your script and then "extends State" in the script you want to inherit from. You can also just do "extends" with a path to the script, but that's cludgy.
excuse me, i believe i might be have noticed an issue with this node-based setup, and i figured i'd ask to see if im missing something. i'm using this currently, in the process of setting up a very basic testing character. it has an Idle state, and if the player's Input.x variable is anything but zero, it calls switch_state from the StateMachine and switches to the Move state. in doing some debugging, i did a test where i called Engine.get_physics_frames() (gets the current number of physics frames that the engine has run in total) and it noticed something. If you have the game print the current physics frames immediately before calling switch_state, and then immediately before move_and_slide is called inside the Move state, the second call is 1 frame more than the first one. this seems to imply to me that, the point where the game detects the Input.x and switches states, to the point where the character is actually moved via move_and_slide, does NOT happen on the same physics frame (as i believe it normally does) Is this true? am i misinterpreting the numbers?
That's correct. On a given frame, the current state's logic is ran and a transition occurs if necessary. While the relevant enter and exit functions will run the same frame as the transition, frame-dependent logic does not, as the current frame has already been processed by the previous state. While you could have the new state process the current frame a second time, the implementation I show here isn't unusual in its one frame delay as it prevents frame data from being processed multiple times in the same frame.
@@TheShaggyDev so the one frame delay in movement probably isnt something to worry about, you think? thank you kindly for taking time to respond, by the way. i worry im doing things wrong a lot in coding
@@MrBoingus for most games, I think it's fine. If you had a game that required high precision inputs, like a fighting game or a high precision platformer, maybe you'd want to not have that delay. I also wouldn't stress tooooo much about doing it wrong if it works for you. We all code something ugly but functional at some point. Just gotta learn for next time 😊
if its an issue of your own personal time, i might be able to pay you something for the help. i know this could take away from time you could be working
I’ve tried this in a test project but am having problems with the process_input function. After one state checks Input and returns another state the new states process input doesn’t get called
Yep, that's to be expected. This state machine lets one state respond to one input, so if a new state is returned, it has to wait until the next input event to respond. You'll need to modify the project if you need to let multiple states respond to the same input, though I don't know if that's really a traditional approach to state machines.
That's one option. For something like death, I usually let the parent entity short-circuit that path, though, since there may be some higher level effects that need to be taken care of as well (game over screen when the player dies, etc)
Hello im pretty new to godot and coding in general, im having this error message pop up and I have no idea how to fix it, "Invalid assignment of property or key 'parent' with value of type 'CharacterBody2D (Player)' on a base object of type 'Node'." the error is referring to this part of the code. "func init(parent: Player) -> void: for child in get_children(): child.parent = parent" Hoping someone can explain what the issue is! thank you
Make sure that your states are inheriting from the BaseState class you've created, ie your state nodes should have a script on them that has "extends BaseState" at the top instead of "extends Node"
@TheShaggyDev I do believe my states are inheriting my base state, but it is quite possible I didn't set it up correctly! Just to clarify, the base state is just a script not attached to any nodes, with the class name "state" and then when creating a new script you just make sure they are inheriting the original base state script? I did manage to find a solution that seems to work, but I'm not sure if it will have any unintended side affects, Even so it would be nice to understand why this original method gave me trouble! I appreciate you taking the time to respond. Thank you
@@TheShaggyDev I have the same issue here and my Idle state for example begins with 'extends State' as you have done in your example project. Not sure what the solution is currently or where I've gone wrong, but I'll keep digging. If you think of anything let me know.
I found the solution. Don't try and test this with only one state (in my case, idle). Finish the code for all your states and then it works flawlessly. I copied the state code not in the video from the project. Works great!!!
I don't see how this lets you reuse states on different objects. If you try to reuse your move state node on an object that can't jump, you'll have to make a new version of the move state script that doesn't allow transitioning to the jump state. Then when you want to tweak how the move state works for all objects, you'll have to make that same change multiple times for each object that uses it.
For this specific situation you can just add a bool called can_jump to the move state. Then only allow the transition for objects that can_jump. No need for multiple variations of the move state.
I don't understand why you would ever do this. That would result in *so* many nodes and *so* many scripts. For every state, you have a new node and script.
I realized coding things such as sprite.flip_h = true. Is not a good practice, the best option is to do it from an animator... Maybe this character does not have an animator.
If you just want a quick, one-time download, go to the repo root (github.com/theshaggydev/the-shaggy-dev-projects/tree/main), click the green "Code" button, and then you can download a zip file.
@@TheShaggyDev thanks. I think I understand the state machine but parts of the code don’t recognize the class_name and I’m trying to figure out what I’m missing
@@salmonbamminfish2925 as long as it's set up like in the sample project, it should work, but sometimes you need to restart Godot for class_name changes to take effect
"Let's go through this line by line" -> *proceeds to skip all functions*. As a beginner it's incredibly frustrating that every single state machine tutorial skips over major parts of the things they are supposed to teach. For example: I'm currently trying to find from Godot documentation whether functions enter() and exit() are default functions (like _ready()) or not, or how they work or why they are defined here, but once again the tutorial doesn't tell it. Googling enter() and exit() gives some info, but what exactly makes Godot call these custom functions and when? You just write them and they somehow magically work? For a beginner like me, a state machine is incredibly difficult to figure out and this is, like, the fourth tutorial that does the exact same mistakes. The biggest problem with these tutorials is that they never seem to tell WHEN or WHY stuff happens, like what is the logic. I'm inferring that maybe the enter() function is called automatically when state is entered yet I'm unsure why. Another thing that is difficult for a beginner is that you have two things running in parallel: game logic and animations. This causes some weird stuff to happen like being able to change direction during dash animation. None of these state machine tutorials give tools to understand the process better.
From what I can remember about how state machines work, the enter and exit functions are called from within the states themselves. For the example from the video, when the player is initialized in the world the _ready() function inside the player calls the state_machine's init() function. Inside of the state_machine we can see what the init() function does. Looking at the code it seems that all we do in this function is tell the state machine who the parent object is, and then tell the state machine to enter a new state using the change_state function. The change_state function takes in a state as a parameter so that it can know what state to enter. Looking in the body of the change_state function, the current_state is fed the parameter of the change_state function and then the enter() function is called from within change_state. This way, every time a new state is entered, the enter function in the state itself is called. This is how we tell the object what to do when the state is entered. Each time we need to exit a state we use a condition that tells the state machine to enter a new state. Inside the idle state, inside the process_input() function, we tell it what state to enter based on what input is pressed. When we press the "jump" button we enter the jump state. We do this by returning the jump_state inside of the process_input() function. The way that we return this is by telling the function that it will be returning a variable of the type State at the end of the function declaration (the part after the arrow operator). This takes us back into our state_machine code. The process_input() function holds a local variable called new_state. It sets this variable equal to the output of the process_input() function in whatever the current_state is. So going from idle to jump it would be something like, "var new_state = idle.process_input(jump)" This is only the way the code itself is interpreting it, not the way it is literally written. The next line says that if a new_state exists, then we will execute the following code. The code that follows would be translated as, "change_state(jump)." This is how we will be calling the change_state() function, which will in turn, call the enter() function on the jump state. Sorry for the wall of text, but I hope this helps.
@@PeaceInExile Ok, this helps a bit. Can you also comment on why, in the video at 8:55, there is a function called func process_input(event: InputEvent) -> State: Yet it does not reference the "event" at all. Instead it takes Input, which I presume is available inside the state itself?
@@zerofallstudiosi didn't say that. i said not in gdscript. the reason is that the overhead of gdscript composition is way too large. specially in the scene tree. what is needed for a proper state machine to run efficiently is inlined c++ functions. i'm not saying gdscript shouldn't be used for anything' i'm saying you will end up having something like 100x overhead for this usage.
As a newbie to Godot and game design but not to coding in general, the exploration of using a node based approach to state machines was fairly eye opening. Thanks!
This is a great explanation and breakdown of state machines. State machines are one of those things that beginner game programmers should learn as soon as possible.
Of all the YT videos out there on state machines this one is the most straightforward and easy to understand. The idea of each state as a “hot-swappable” brain made it really click for me. Thank you for making this and looking forward to the next video!
i just wanted to let you know, thank you for leaving text-based versions in the descriptions. :)
Very concise. As a beginner to Godot I understood what State Machines were, just didn't understand all the code. This video has certainly helped me out; although, I did have to watch it a few times to get it down. Very well done!
This is my favorite video on Godot state machines. Love the node-based approach, simple - clean, effective. Thank you Shaggy!
Thanks for sharing your info with us. I had an old game where the character has several states (run, slide to a stop, turn around, crouch, jump, climb up, climb down, use action) and the code was growing untenable. I've been wanting to go back and add to the game, but the state controller is over a hundred lines and so messy. I'm converting it to your style of node base states and it's so clean. I appreciate it. And your website version of the explanations is an awesome addition. I'm sure I'm dozens of web clicks on it. Thank you!
Thanks! Always happy to hear about people using the site! I prefer reading to watching so I like to offer that to others like myself.
It's been a while since I worked with state machines, so I really appreciated this video as a refresher.
Nice to see this topic covered again for Godot 4.
Thanks for including the Enum + Match statement approach for making simple state machines. I exclusively use this approach for minions/enemies as its less resource hogging compared to the State Pattern approach.
The node based State pattern approach is fine to use for Player character and Enemy Bosses.
Thanks! I had a similar implementation except I was using the processing of each of the individual nodes, I think I ran into some overlap where some states were still running while the new states were active. Your way of using the parent's processing sorted this out.
Thanks :)
As for giving the state machine a reference to the parent, you can use the state machine’s `owner` property; that will always be initialized to the scene root: in this case, the player. Even if the hierarchy changes, whether when you restructure the Player scene or later during runtime, a node’s `owner` won’t change unless you change it manually using `Node.set_owner()` in code.
this is the best video about node base state mechine in Godot. the examples helps A TON! ty for the video!
Great video! Most of the time, I use almost exactly this approach. The only difference I have is that my separate states fire signals that allow the owner of the state machine to decide what its next state will be based on the owners properties or configurations. By not having separate states reference other states it means that all combinations of states can be used, since the owner of the state machine controls what happens next based on individual state signals. Sometimes these states even have their own 3D nodes in order to determine if it sees a target using a raycast for example. Child nodes of separate states can be interchanged per scenario, thus making it customizable per instance of that single state.
Oh I like that idea! Signals would give you a good bit of flexibility, as you've mentioned.
Keep it up man, waiting on the next more advanced FSM tutorial!
Shaggy Dev. This was incredibly useful. Thanks for sharing.
Finally a basic explanation of fsm that i can understand. TBH, i never fully understand state machine even after watching many tutorial and sample project. You just make it all make sense. Turn up, i already using some kind of state machine in my project.. albeit primitive one 😆
Thank you, sir!
How much was i waiting for this, thanks !
this is quite genuinely better than sliced bread. thank you so much for this
Thanks, really needed help with this. Planning on making a platformer game and this really helps achieve that, straight to the point and easily explained. You've got a sub from me, looking forward to more State machine Tutorials for Godot 4
Yes please more in depth one. Keep it up!
Damn it’s kinda funny seeing this after I bumbled my way through dealing with a character that could swap abilities based upon powerups in game in my own project. I used messy if statements to get it working but this makes much more sense.
ahh, a great recreation of your classic videos. this is the state machine foundation i've been using in godot ever since your original videos. i'm EXTREMELY excited for the next video on (unless i misunderstood) what to do if you need a more complex state machine! perhaps one with a ton of different states...??
Great explanation. I have a game here with a player built using node composition. I believe my next step would be to extract those node that handles jump, movement and so on to their own state. I'll try to do it without copying exactly what you did, but I could grasp the general idea: 1 state manager has many states, which extends the base state node. The state manager will handle the logic between states, while the states has logic for handling input, animation and gravity as it seems fit
I've been using the node-based approach for a while now, but using a generic state script + lambda functions and overwriting them in the state-machine script as needed.
thanks for the video, so useful, waiting for the next
I can't wait for the next video!
This is a pattern I utilize greatly, and always advise beginners learn to use. My current opinion on the best implementation for node-based state machines is a single node that behaves both as a state and a machine, which allows for hierarchical state machines, although it can lead to some mess if structured improperly.
No way, I was just watching your old videos on this topic because I started studying finite state machines, what a coincidence lmao
Thank you!
good stuff!
This is the best state machine explanation around, yet i still cant wrap my mind around it sommehow. Maybe its the language barrier that sometimes gets to me. But awesome vide as always love your content!
It's because you don't try by yourself, videos are great, yeah, but ONLY after you've struggled a lot
Great!
Great general overview. Really easy to follow and implement. That said, i do have some issues with using it when i want to react to other signals.
In my case, its for character attacks that can combo. I want to trigger a knockback effect on each hit, so i have a knockback state with special behavior, and then each state listens on a signal that the hurtbox has been entered, and transitions to the knockback state. What happens is my signal in the Idle triggers, and transitions to the knockback state, where the signal for the knockback state triggers and applies its effect again. This somehow happens even when i check if the state is active in the signal...
You really make hight quality videos! Thanks alot for all of them!
I wonder if you'll ever make a video of an implementation of utility ai in godot 4. Would really love that!
Thanks! And possibly! I covered the high level design in my last devlog, but didn't show much code related to it, so might be worth diving in further.
Good stuff 🔥
Don't forget to try your own things without looking at vids or else you won't progress guys 😉
IMO, using Nodes for states falls down hard for larger projects. We use Resources for states instead, with a StateMachine node holding an Array of them. States can be dropped into the statemachine's inspector. The states have initialize, enter/exit state methods and a process method that's called by the StateMachine node every frame for the current state.Much cleaner than a huge list of nodes in the scene to enable/disable all the time. ANd Resources don't need all the extra internal bulk of Nodes. IMO, using nodes is just asking for a maintenance nightmare as soon as the project grows a bit. And I don't even think Nodes is simpler for new devs. But hey! They are a thousand ways to do everything. Just my thoughts. Peace.
for simpler sate machines (like your turret) i like to use a setter to handle changing state.
would love an in depth video on hierarchical state machines in godot 4
i think the node based approach might be better in some situations as if we wanted to add and remove possible states for example
Please please pl3ase do more on state machines this helelped so damn much
My implementation is very similar except I don't like specifying the player type for the parent as this ties to the state machine code to only work for the player class. Instead, I used CharacterBody3D since I am creating a 3D game. This means enemies could potentially use the same scripts but the down side is not having code completion for player specific variables. I guess you could cast the parent to a Player type within the individual states but I am still working that bit out. Good video.
Funnily enough, my implementation of a state machine is more or less the same.
Except, that for some reason, I decided to switch between states based on strings, rather than exporting them as variables as needed for each state. In hindsight, I really don't know why I came up with this idea myself! :D
Oh, and I also did decide to change states manually, rather than as a return value of a function.
The Godot state chart addon is good and handles a lot of this for you, but lacks some of the flexibly of writing your own. I've used it in a couple of projects and really like it so far. It's worth checking out.
Thanks for explaining things. Question I have is what if your "idle" state needs to access another node inside the character scene. Like to get a particle system and enable it. Its okay to use a reference to that from the "Idle" class? Seems weird because you are referencing up the hierarchy instead of down.
Sure, it is what is is sometimes. I'd probably @export that reference, but you could also pass it in like you do the player if you'll need it a lot of places.
It is so excited ❤
But how we practiced can you please suggest
Thanks for the great breakdown :) we question, what is the "event" used for in process_input? As you don't seem to use the value in your example?
That's the default information that is provided about an input. To hook into input events, you have to at least accept it in your "_unhandled_input" function, but I pass it to the states in case I want to read that information.
See: docs.godotengine.org/en/stable/tutorials/inputs/input_examples.html#input-events
How would you handle concurrent states? For example if the player is attacking mid jump or while moving?
I'll touch on this more in the next video, but there's nothing wrong with multiple state machines if you have independent states to manage, such as for a run and gun type of game.
I met you thanks the introduction to Utility AI video. I would like to see a video about its implementation in Godot.
I think this was a really good explanation on state machines. The only real criticism I have is that its really hard to follow the Node approach, even with the source files, for the sake of implementing in a project. The actual states themselves are fine, but there's no mention of how to use the state changes / where to manage the state changes & how.
Nvm the code does a pretty good job at it, i just suck
It would be interesting to see how you handle various different types of Entities (Player, NPC, Object)
I'm working on a 3D game and I like your approach. I got one question though - do you think it is reasonable to have two state machines for 3D? Because I want to have legs animated when running, but you also can hold item which changes how the arm bones behave and I'm not sure if this is the correct approach, i.e. one state machine for legs and the other for upper body.
Sure! That's exactly what I talk about in the follow up video to this one. It's not uncommon to have multiple stateful things on one entity.
yeah really is great technique, for no use match and more clean code, one mob from my game the main code has more line than bible using match.
I'm going to watch your other video on state machines next to figure this out, but I'd like to raise a question. What is and isn't a state in a state machine? As far as animation handling goes, this system is flawless. Each state has a distinct animation and that part is easy to get for me. But for movement handling, jump and fall control the opposite ends of y-direction movement, while move controls both directions of x, and idle is responsible for the lack of either. Since platformers tend to have x-direction capabilities in air, three of the four states can control when the player moves left or right.
I think the concept of states being both directly responsible for movement (jumping velocity is instant once entering the state) and indirectly able to be controlled based on input without switching states is tripping me up. Outside of these four main actions, I'm confused on what actions should and shouldn't have separate states. Overall the idea of "swapping brains" with states is clear and concise, I may just be thinking about this too rigidly.
Rather than breaking it down into movement or not, I like to think of it as "Is this something that would require conditional logic to process?" I might need to do X if I'm falling or Y if I'm not, for instance.
The next video should help clarify how to build out functionality and reuse some code to help with some of what you're talking about, but I think you've also actually stumbled upon a common criticism of state machines without even realizing it: they can get complicated pretty quickly.
How important is it to use the optional static typing here? I couldn't find a reason to do so in the GDScript style guide
I'm assuming it's just preference
It is indeed just preference, but I do recommend it once you're comfortable with general coding. It makes it clearer to future you and others what your code is doing, it makes the code completion hints in Godot more helpful, and there are some small performance improvements from using it. Plus, in the case of this channel, it gives a better idea of what I'm doing without having to explicitly call out every variable.
Again, though, totally optional and not something you have to worry about right away.
when I try to run this scripts I get an error that reads "invalid call. nonexistent function `enter` in base `Nil`" in the state_machine node, func change_state final line `current_state.enter()`
Make sure you've set the starting state on your state machine. That should be an exported node you can edit from the inspector.
Do you go through doing this in the video? I'm trying to assign the starting state in my state machine but none of my nodes are able to be assigned@@TheShaggyDev
@@Chase_Is Are your states inheriting from the State class? The export should be typed to State, so will only accept nodes that inherit from State. Can take a look at the sample project if you want to see how everything should be set up.
I have everything that you have in the file in your description. All of my states all extend the State class. So idle is the same as what you have in your sample@@TheShaggyDev
Oh I fixed it. All of my States were extending state except for the actual State script. Thank you so much for the reply, your videos are so helpful!!@@TheShaggyDev
So this may be a dumb question, but I'm trying to learn this while doing a state machine on a simple racing game, but I'm getting my wires crossed somewhere. On the state machine, I need to be able to control the vehiclebody3D, which is of course its parent. But the VehicleBody3D controls things like steering and throttle. The state machine doesn't seem to be able to access those functions (Or exported variables), even when trying to access the parent (Or parent of the parent, to be fair, as the actual states are another layer below the state machine).
Any idea how to have the states "latch on" to those functions so they can be modified? Or am I aiming for something fundamentally flawed?
Hmm, I'm afraid I'm not aware of any reason why you couldn't use this technique on the vehicle. Though I'm not overly familiar with the VehicleBody3D node, I don't think there's any specific reason why it wouldn't work.
@@TheShaggyDev
All good, I'll keep playing around with it. Thanks for the reply!
If you embed a separate 'state machine' and define local 'states' for each type of object 'node', how do you know if you're getting the main supposed benefit of 'state machines' in that you're handling all possible states (and combinations of states...) in a deterministic way?
What if not every piece of data in your game is trivially synchronous?
What if you have a non-trivial amount of nodes, and in aggregate, they may not complete their state updates within 16ms?
What if you have a non-trivial game that has at least one behavior, data or operation than affects a 'state' that could take more than one frame to calculate?
The states are still organized on that object, but there's no need that every object needs to run through one large state machine that keeps everyone in sync. They can, and will, change states at different times depending on the interactions each object has with the world. These small per-object state machines have a minimal impact on performance, which will be a game dependent detail anyways. If the state's can't update in time, profile and adjust where needed.
While a lot of common state machine uses in games should be able to run synchronously just fine, long running or asynchronous tasks won't impact the implementation that significantly, nor will that make the state non-deterministic. We still got to this long running task based on some set of inputs to the machine. Depending on the exact use case, a processing state for that object might help to make it clearer what's going on and help prevent invalid state changes while it's processing everything, but that can, again, vary based on the game.
I think you could remove the player related variables from the base State class in a way it becomes generic and reusable in objects that are not players
isn't class_name supposed to be under extends in scripts? 5:57
Either way is acceptable in Godot! I personally tend to put it first as that mirrors other programming languages where you typically have the pattern of "X is a subclass of Y"
is there a reason why you are not simply making the animations and state machine variables on your player node exported vars?
on one hand you say that not passing the reference would break the code if you change the node structure but on the other hand you hard code the path to your state machine. just trying to understand your reasoning as i‘m currently in the process of switching from unity where i heavily used inspector set paths
You could certainly do that as well*, but I'm ok with the parent knowing its children. It's the child knowing its parent I'm more cautious of.
* There was an issue in Godot for a bit where a top-level exported variable would point to the wrong node when multiple instances were in a scene, but I believe that's been fixed now.
I'm confused 5:45. where does this class name thing go?
That should go in your script holding the base state implementation (see "state.gd" in the sample project)
✨🙏🏼✨
could owner property simplify the code so that we dont have to pass the parent down?
Sure, that would work just fine for something like what's shown in the video.
I don't fully understand. Can someone tell me, what in that code (of the node based approach) causes the code to know, which State is inactive? With match, I get, why only one gets selected. But when I "return jump_state" for example... How does it know, that idle_state is no longer active and should not be executed anymore?
The trick is in the code for the State Machine node. When a state returns a new state, that triggers "change_state()" in the state machine, which changes which node is marked as the current state. As the machine only allows for one state to be active at a time, only the current state is ever processed and given inputs from the parent.
how do you make it auto-complete in the states?
i'm using my own component "move_component" witch is a class "MovementComponent"
I'm passing it to the state_machine and to idividual states aswell
but when I use it inside the a idividual state is dosen't auto-complete when I'm writing a function, it works, but I need to keep bouncing to the component script to get the functions...
As long as you type your variable (ie "move_component: MovementComponent") it should autocomplete for you, though sometimes Godot can get a bit confused on types...
Hey so there arent any errors in the code itself, but when trying to run the game it gives me the error (Invalid set index 'parent' (on base: 'Node') with value of type 'CharacterBody2D(Player)').
Not sure how to fix this and any help would be greatly appreciated.
(Also i've been mixing and mashing tutorials together so maybe that could be an issue)
I thought I was crazy at first but they did tweak state machines quite a bit. I get whiplash from all of these changes sometimes. Open source engine problems, I suppose.
Great content! But how come I can't download ZIP for this project in Github? It's so much easier to understand that way.
Go to the repo root and you can download everything as a zip: github.com/theshaggydev/the-shaggy-dev-projects/tree/main
I'm utilizing C#, and working through this tutorial and a conversion process from GDScript. What would be the equivalent of this section of the Statemachine code:
func init(parent: Player) -> void:
for child in get_children():
child.parent = parent
in C#?
public void Init(Player parent)
{
foreach (Node child in GetChildren())
{
child.SetParent(parent);
}
}
@mel-du-studio-coco thanks! Though, i don't think SetParent exists (I get an error saying it doesnt). What would be the alternative?
here the 'set parent would be a custom function that you've made that assign the property 'parent' of your state script.
child.parent = parent
@@zacklewan4183
Whats the difference between state.gd and state_machine.gd, the former doesn't have any owner of a node while the latter has whichs state_machine.tscn?
In short, state.gd handles the state-dependent logic where state_machine.gd handles coordination between states. So you might make a run state using state.gd, but let state_machine.gd handle transitions between states, dependency injection, etc.
how do I create a State class that godot will allow my state scripts to inherit? Because right now I get "Invalid inhereted parent name or path." whenever I create a script for my classes that tries to extend my State class. I am at my wits end with this.
There are two ways to inherit from a class in GDScript. The easiest is to make sure that you have "class_name State" (or whatever the class name is) at the top of your script and then "extends State" in the script you want to inherit from. You can also just do "extends" with a path to the script, but that's cludgy.
excuse me, i believe i might be have noticed an issue with this node-based setup, and i figured i'd ask to see if im missing something.
i'm using this currently, in the process of setting up a very basic testing character. it has an Idle state, and if the player's Input.x variable is anything but zero, it calls switch_state from the StateMachine and switches to the Move state.
in doing some debugging, i did a test where i called Engine.get_physics_frames() (gets the current number of physics frames that the engine has run in total) and it noticed something. If you have the game print the current physics frames immediately before calling switch_state, and then immediately before move_and_slide is called inside the Move state, the second call is 1 frame more than the first one.
this seems to imply to me that, the point where the game detects the Input.x and switches states, to the point where the character is actually moved via move_and_slide, does NOT happen on the same physics frame (as i believe it normally does)
Is this true? am i misinterpreting the numbers?
That's correct. On a given frame, the current state's logic is ran and a transition occurs if necessary. While the relevant enter and exit functions will run the same frame as the transition, frame-dependent logic does not, as the current frame has already been processed by the previous state. While you could have the new state process the current frame a second time, the implementation I show here isn't unusual in its one frame delay as it prevents frame data from being processed multiple times in the same frame.
@@TheShaggyDev so the one frame delay in movement probably isnt something to worry about, you think?
thank you kindly for taking time to respond, by the way. i worry im doing things wrong a lot in coding
@@MrBoingus for most games, I think it's fine. If you had a game that required high precision inputs, like a fighting game or a high precision platformer, maybe you'd want to not have that delay.
I also wouldn't stress tooooo much about doing it wrong if it works for you. We all code something ugly but functional at some point. Just gotta learn for next time 😊
@@TheShaggyDev so i actually am making a fighting game 😅 are you able to tell me how to remove the delay? or would it be too complex to explain?
if its an issue of your own personal time, i might be able to pay you something for the help. i know this could take away from time you could be working
I love you platonically
I’ve tried this in a test project but am having problems with the process_input function.
After one state checks Input and returns another state the new states process input doesn’t get called
Yep, that's to be expected. This state machine lets one state respond to one input, so if a new state is returned, it has to wait until the next input event to respond.
You'll need to modify the project if you need to let multiple states respond to the same input, though I don't know if that's really a traditional approach to state machines.
also if you had a death state how would you do that? would you have a transition from every other state to the death state?
That's one option. For something like death, I usually let the parent entity short-circuit that path, though, since there may be some higher level effects that need to be taken care of as well (game over screen when the player dies, etc)
Hey, if anyone could help, when I call for the state machine to initiate itself I receive and null instance. Why is this so?
Hello im pretty new to godot and coding in general, im having this error message pop up and I have no idea how to fix it,
"Invalid assignment of property or key 'parent' with value of type 'CharacterBody2D (Player)' on a base object of type 'Node'."
the error is referring to this part of the code.
"func init(parent: Player) -> void:
for child in get_children():
child.parent = parent"
Hoping someone can explain what the issue is! thank you
Make sure that your states are inheriting from the BaseState class you've created, ie your state nodes should have a script on them that has "extends BaseState" at the top instead of "extends Node"
@TheShaggyDev I do believe my states are inheriting my base state, but it is quite possible I didn't set it up correctly! Just to clarify, the base state is just a script not attached to any nodes, with the class name "state" and then when creating a new script you just make sure they are inheriting the original base state script?
I did manage to find a solution that seems to work, but I'm not sure if it will have any unintended side affects, Even so it would be nice to understand why this original method gave me trouble!
I appreciate you taking the time to respond. Thank you
@@ben112234455 that's correct. If you want to keep troubleshooting, what was the solution you found?
@@TheShaggyDev I have the same issue here and my Idle state for example begins with 'extends State' as you have done in your example project. Not sure what the solution is currently or where I've gone wrong, but I'll keep digging. If you think of anything let me know.
I found the solution. Don't try and test this with only one state (in my case, idle). Finish the code for all your states and then it works flawlessly. I copied the state code not in the video from the project. Works great!!!
Ok Fine. But why not just use the statemachine already implemented in an animationtree?
I don't see how this lets you reuse states on different objects. If you try to reuse your move state node on an object that can't jump, you'll have to make a new version of the move state script that doesn't allow transitioning to the jump state. Then when you want to tweak how the move state works for all objects, you'll have to make that same change multiple times for each object that uses it.
For this specific situation you can just add a bool called can_jump to the move state. Then only allow the transition for objects that can_jump.
No need for multiple variations of the move state.
Even easier just return the blank base state that does nothing via the export variables
I don't understand why you would ever do this. That would result in *so* many nodes and *so* many scripts. For every state, you have a new node and script.
I realized coding things such as sprite.flip_h = true. Is not a good practice, the best option is to do it from an animator... Maybe this character does not have an animator.
I'm the only one still finding this difficult to understand 😪
how in the world do you download crap off of github
If you just want a quick, one-time download, go to the repo root (github.com/theshaggydev/the-shaggy-dev-projects/tree/main), click the green "Code" button, and then you can download a zip file.
@@TheShaggyDev thanks. I think I understand the state machine but parts of the code don’t recognize the class_name and I’m trying to figure out what I’m missing
@@salmonbamminfish2925 as long as it's set up like in the sample project, it should work, but sometimes you need to restart Godot for class_name changes to take effect
@@TheShaggyDevthank you so much. I am very blind and missed the extends node inside the base state class. Appreciate your help
@@salmonbamminfish2925 Glad you got it sorted out!
"Let's go through this line by line" -> *proceeds to skip all functions*. As a beginner it's incredibly frustrating that every single state machine tutorial skips over major parts of the things they are supposed to teach. For example: I'm currently trying to find from Godot documentation whether functions enter() and exit() are default functions (like _ready()) or not, or how they work or why they are defined here, but once again the tutorial doesn't tell it. Googling enter() and exit() gives some info, but what exactly makes Godot call these custom functions and when? You just write them and they somehow magically work? For a beginner like me, a state machine is incredibly difficult to figure out and this is, like, the fourth tutorial that does the exact same mistakes.
The biggest problem with these tutorials is that they never seem to tell WHEN or WHY stuff happens, like what is the logic. I'm inferring that maybe the enter() function is called automatically when state is entered yet I'm unsure why. Another thing that is difficult for a beginner is that you have two things running in parallel: game logic and animations. This causes some weird stuff to happen like being able to change direction during dash animation. None of these state machine tutorials give tools to understand the process better.
From what I can remember about how state machines work, the enter and exit functions are called from within the states themselves. For the example from the video, when the player is initialized in the world the _ready() function inside the player calls the state_machine's init() function.
Inside of the state_machine we can see what the init() function does. Looking at the code it seems that all we do in this function is tell the state machine who the parent object is, and then tell the state machine to enter a new state using the change_state function.
The change_state function takes in a state as a parameter so that it can know what state to enter. Looking in the body of the change_state function, the current_state is fed the parameter of the change_state function and then the enter() function is called from within change_state.
This way, every time a new state is entered, the enter function in the state itself is called. This is how we tell the object what to do when the state is entered. Each time we need to exit a state we use a condition that tells the state machine to enter a new state.
Inside the idle state, inside the process_input() function, we tell it what state to enter based on what input is pressed. When we press the "jump" button we enter the jump state. We do this by returning the jump_state inside of the process_input() function. The way that we return this is by telling the function that it will be returning a variable of the type State at the end of the function declaration (the part after the arrow operator).
This takes us back into our state_machine code. The process_input() function holds a local variable called new_state. It sets this variable equal to the output of the process_input() function in whatever the current_state is. So going from idle to jump it would be something like, "var new_state = idle.process_input(jump)"
This is only the way the code itself is interpreting it, not the way it is literally written. The next line says that if a new_state exists, then we will execute the following code. The code that follows would be translated as, "change_state(jump)." This is how we will be calling the change_state() function, which will in turn, call the enter() function on the jump state.
Sorry for the wall of text, but I hope this helps.
@@PeaceInExile Ok, this helps a bit. Can you also comment on why, in the video at 8:55, there is a function called
func process_input(event: InputEvent) -> State:
Yet it does not reference the "event" at all. Instead it takes Input, which I presume is available inside the state itself?
@@PunCala I haven’t come across a reason to use that parameter yet. For now I’ve been ignoring it
you should NOT have state machines in gdscript for a production build.
@@zerofallstudiosi didn't say that. i said not in gdscript.
the reason is that the overhead of gdscript composition is way too large. specially in the scene tree.
what is needed for a proper state machine to run efficiently is inlined c++ functions.
i'm not saying gdscript shouldn't be used for anything' i'm saying you will end up having something like 100x overhead for this usage.
Oh yeah, so "simple" that my code isn't working.