It's such a great video, top-quality content as always. I especially appreciate providing the text-based version. It must be a ton of work to design, write and edit this kind of content. I just wanted to let you know that you actually inspired me to start my own tutorial channel! :) Keep up the good work. Cheers!
Thanks so much!! Watched your first video and it was really good! You've already figured out how to make the architecture bits more interesting than I have 😅 Good luck with your channel, though based off of what I've seen I'm sure you'll do great!
@@TheShaggyDev Thanks man, I REALLY appreaciate you for taking the time to answer and watch my video! You are even more cool than I though. Thanks again!😁
i'd like to suggest the creation of a discord server where game devs who likes clean code and good architecture can could home :) On my daily life I'm a senior backend developer and I'm really missing a community with a more advanced approach to code
Thanks so much for this. It took me three days to wrap my head around state machines, but thanks to your videos and downloadable examples, I've got state machines handling characters' actions in the game I'm working on
I've been working on an FPS template for ages and I use a concurrent state machine. A state machine that's just dedicated to movement and another to controlling the active weapon, shooting ect.
This is awesome! A lot of this flew over my head as I'm pretty new to game dev, but overall I was still able to follow. I also really appreciate the book recommendations at the end!
Programming a gun for a bullet hell game. Started out as a bit of a mess between reloading, single shot, burst shot, full auto. So much simpler now, I just drag and drop firing mode nodes onto the weapon. Took it a step further and attached projectiles to those modes, and images so that the UI area showing the fire mode auto-populates with icons.
gah - thank you for this video... i've been exhausting myself trying to learn more about godot-specific approaches to solving a number of the issues/challenges you mention here
Re concurrent/competing states: the mathematical/geometric abstraction for that would be a multi-dimensional state space in which every allowed is represented by a point. A state transition is then like jumping from one point in that space to another - where some transitions are allowed and some aren't (the single state machine can be thought of as a one-dimensional number axis - note that distance between the points does not really play any role here, except maybe for aesthetics). If the dimensions/coordinates are "orthogonal", meaning that each value on each dimension is possible regardless of the other dimension, it makes sense to implement it as two (or n) state machines (like having a separate value=scalar for each state). But if there are many dependencies, it may make more sense to think of a single state machine instead, which manages a combined state like a point in the state space with n coordinates.
I watched this video and it's precursor a while ago, and couldn't recall anything from it besides using nodes as states. This weekend I made my own implementation before rewatching these, and I did a surprising amount of things the same way. It's probably a combination of my subconscious, and the fact that there is a natural solution in Godot using nodes. I will detail some cool differences below.
Firstly, I made extensive use of custom component classes, such as a move component that moves a chosen physics body. Each state has export variables for the components it may affect (dependency injection). If one is left blank it won't error, so there is some flexibility. I also tried decoupling transition logic from state logic. I made a separate class of state transitions which could be children of states. That way, the transition logic can be customised for each entity. For example, some entities may have additional states to transition to from idle. The idle state only manages what it needs for an entity to be "idle", not when to change to another state.
I watched your other state machine videos months ago and I honestly didn't like the implementation. But I'm glad I came back, I didn't realize this was new, and I was actually making a similar input thing for my game.
Thanks for checking it out again! Part of the reason I wanted to revisit the subject for Godot 4 is that, in retrospect, I also felt the original videos were a bit lacking. Still plenty of options in how to make a state machine, but I wanted to make something more comprehensive than before if going for the node-based approach presented here.
I would like to know how do you deal with signals to implement hitboxes and hurboxes. I'm creating the sword attack for the main char I need to implement the hitbox for the sword and the hurtbox for the enemy. I did it with the same component based approach, I created a hurtbox scene that is just an Area2D with the attribute damage and group "has_damage" and created a hurtbox scene that is just an Area2D with the group "has_health" that holds the max health and current health. To connect it to the state machine and trigger state changes when I hit an enemy, I had to extend the state machine base class to have also the process_area_signal(area: Area2D) -> void and the state base class to have the matching func process_area_signal(area: Area2D) -> State. And now when I hit the enemy, the original signal _on_area_entered(area: Area2D) calls my enemy's state_machine.process_area_signal(area) and trigger the death state or damage state. I don't know if this would be the best approach, I'd to hear more about you and how do you deal with signals and state machines Do you have a discord server?
My approach in the past with signals has been to let the parent object listen and then pass that information down to the state machine, whether with a direct state change or calling a function somewhere, usually because for something like a hurtbox I probably need to manage health, potential s, etc that may need to work outside of the state machine. I'm afraid I don't have a Discord server. May get around to that one of these days...
at 4:00 I wish you showed the boilerplate code because it would really drive home the use of how to set up this kind of composition. please help thanks
A full example is beyond the scope of the video or this comment, but you'll want to set up a custom class / type like you would any other custom class in Godot, type your component reference in the state machine to that class, and then subclass your components appropriately. Then you'll have things fully typed, have autocomplete available, etc. I know that's a really brief description, but there are a few good resources on TH-cam (and elsewhere) that can help you figure out how to do that more in-depth.
I personally came up with the idea of having shared functions being implemented into the state machine. It's easily accessible, often specific to the very object the machine is attached to. A component system as mentioned in your video would be the next step for that, especially usefull for re-useable code parts or when it becomes "too much". The inheritance approach I would stay away from. Not only is it more obfuscating, as you need to go down the hierarchy tree to check up on the function you want to call, it also becomes a real headache if multiple objects want to use the same components/system, but differ widely otherwise. On top of that, generally speaking, inheritance seem to be pretty bad for performance, according to numerous videos on TH-cam. Though I do not know exactly how bad it is and if it holds true in Godot's case (though I very much assume it still is).
those would be symptoms of a poorly set up inheritance structure, not problems with inheritance itself. the indirection / lookups imposed by inheritance is trivial for the purposes of game development
I'm not too familiar with state charts, but from a quick glance at the site, they look interesting, so could be worth trying out. I'm also not very picky about how you handle state management so if it works then go for it!
Hello, I was playing with your state machine Implementation from the first video and I used Godot Resources to inject my movement logic. For example, I have a walk resource that contains some exported vars for walk acceleration, max walking speed, input reading and the logic to apply acceleration and friction. I inject this resource on the fall state, walk state and jump state so the player can move on the X axis during those states. I can record a video explaining it if you want, it's a component driven development I saw here on youtube. When I changed my script to handle the enemy's states, I created a new walk handler for the npc called wander_handler that applies constant Velocity in one direction until a collision happens. So I have two walk_handlers that extends the Walk resource and I can inject them as I see fit. This way I can create two players with the same base scene and make you of them respond to keyboard wasd and the other to arrows or AI. P.s. in my state machine Implementation I try to keep the states implementation unique per context. My player and my enemy shares the state machine object and base state. But each one will have a different node for walk or idle. My enemy just walks around and fall, it has no jump. It moves a little wait for a few seconds, move again. If is on wall it changes direction. If I want to use this state graph to other enemy, I can use the movement component to change it's brain. Or if it's going to be super different I prefer to create new states from the base state to avoid coupling
Thanks for sharing the follow up to your last comment! I really like the technique you've developed. Using Resources makes a lot of sense and I like how you've organized everything.
As for the heirarchical states, i made a dash the same way you did, but since my move script changes its animation in process_physics() based on its current velocity.x, the dash animation is overriden after 1 frame with a movement animation. Any way i can ovveride that in the dash script?
Sure, just use the same techniques shown in the video. It'll depend on how you've got it set up, but you could, for instance, move your animation code to a function that dash state overrides.
In a smash bros like brawler would you just have one state machine for attacks and movement because the direction of movement changes what attacks you can do. Each different attack would be its own state and just have jump/fall states return a different up attack state than idle/move?
Hmm, that's tricky. Iirc, there are actions that can be done while moving, so you still might want to have two state machines. Suppose it would depend on exactly how rigid you want to be between moving and acting.
Hi, been trying to implement this in my own project but it's a top-down game and I couldn't figure out how you would detect which of the 4 animations (top, down, left and right) to play for each state
Hmm, I'd probably track the orientation in a shared data store that each state can update as appropriate and then name the states in the form "orientation_animation", or something like that. Then, the enter function can be updated so that it plays the animation name given to it, but prepends the orientation to the animation name. Just one way of doing it.
This tutorial is absolutely fantastic, and I've learned a great deal from it. Thank you very much for sharing your knowledge. I have one observation regarding the "move_component". I noticed that while you've declared types for all parameters and variables, the "move_component" was an exception. Would it be possible to encapsulate these functionalities in a class like "MoveController"? This class could include fundamental methods such as "get_move_direction()", "wants_to_jump()",... In "CharacterBody2D", you might then add a node with a new script titled "PlayerMoveController" that inherits from "MoveController" and overrides certain functions. Within "PlayerMoveController", you could manage controller inputs, and in NPCs, automate certain behaviors. Ultimately, this approach would allow for the specific type declaration for "move_component" using "MoveController", enhancing the robustness and readability of the code.
Yep! You could certainly set this up in such a way as to have typed support all throughout, such as via the method you've mentioned here. I think overall that's a good idea, and it's something I'd normally do. The only reason I didn't do it here is that the move component is so simple, and I find that too much boilerplate can sometimes throw people for a loop.
Hey. I'm having an issue when I have multiple instances of an object, and when one of the state's emit a signal, every instance reacts to it. Any general thoughts why that could be? I recall there being an inspector setting for this, but can't remember where I heard it. Thanks for the video!
So much great information, thanks for the very good video! I have a question: So I've exported variables, friction, acceleration and speed in the walk state. Now I also want to move horizontally while I am in the jump State. Do I have to copy the export variables from the walk state script and paste them to the jump State script and type the exact numbers in to the inspector. Same also for the Fall State. I also found myself copying the function for moving horizontally from the walk state to the jump and fall state. Is there a better solution for this? Thanks in advance for the answer!
Hmm, if it's just variables that need to be shared, you could try the data store technique to make that available multiple places. If you have code as well, could be a case to go hierarchical and define a move state that the others inherit from that can share the relevant code with any state that needs it.
It's kind of hard to follow sometimes, it's unclear which script you are working on at times, or how your project looks in the editor, and I am trying to follow along side your website
Apologies! Since this requires some more advanced techniques, I do move a bit more quickly through the topics in order to give an overview of everything. Website is a great choice, but I'd also recommend checking out the sample project to really see how everything fits together.
couldn't be more perfect timing on this video
This video is magical. You've just answered all of the state machine related questions I haven't found good answers to in one go, thanks so much!
It's such a great video, top-quality content as always. I especially appreciate providing the text-based version.
It must be a ton of work to design, write and edit this kind of content.
I just wanted to let you know that you actually inspired me to start my own tutorial channel! :)
Keep up the good work. Cheers!
Thanks so much!! Watched your first video and it was really good! You've already figured out how to make the architecture bits more interesting than I have 😅 Good luck with your channel, though based off of what I've seen I'm sure you'll do great!
@@TheShaggyDev Thanks man, I REALLY appreaciate you for taking the time to answer and watch my video! You are even more cool than I though. Thanks again!😁
i'd like to suggest the creation of a discord server where game devs who likes clean code and good architecture can could home :)
On my daily life I'm a senior backend developer and I'm really missing a community with a more advanced approach to code
How funny. I watched the GodotGameLab tutorials and ended up finding this channel after looking for more.
@@Zancibar glad you found his content, it's awesome! :)
Thanks so much for this. It took me three days to wrap my head around state machines, but thanks to your videos and downloadable examples, I've got state machines handling characters' actions in the game I'm working on
Glad I was able to help!
Exactly what I was waiting for, right on time too. Was just about to start a Game Dev session.
Answered some of the remaining questions I had about state machines. Thanks!
Your videos on state machine are great! Would love further videos delving into the topic of state machines!
clear and concise, thanks!
I've been working on an FPS template for ages and I use a concurrent state machine. A state machine that's just dedicated to movement and another to controlling the active weapon, shooting ect.
This is awesome! A lot of this flew over my head as I'm pretty new to game dev, but overall I was still able to follow. I also really appreciate the book recommendations at the end!
such a great video, thankyou for all the info :O it so much easier to understand now !
Programming a gun for a bullet hell game. Started out as a bit of a mess between reloading, single shot, burst shot, full auto.
So much simpler now, I just drag and drop firing mode nodes onto the weapon. Took it a step further and attached projectiles to those modes, and images so that the UI area showing the fire mode auto-populates with icons.
gah - thank you for this video... i've been exhausting myself trying to learn more about godot-specific approaches to solving a number of the issues/challenges you mention here
This is great, thank you!
Your videos are always a delight, thanks man!
Re concurrent/competing states: the mathematical/geometric abstraction for that would be a multi-dimensional state space in which every allowed is represented by a point. A state transition is then like jumping from one point in that space to another - where some transitions are allowed and some aren't (the single state machine can be thought of as a one-dimensional number axis - note that distance between the points does not really play any role here, except maybe for aesthetics). If the dimensions/coordinates are "orthogonal", meaning that each value on each dimension is possible regardless of the other dimension, it makes sense to implement it as two (or n) state machines (like having a separate value=scalar for each state). But if there are many dependencies, it may make more sense to think of a single state machine instead, which manages a combined state like a point in the state space with n coordinates.
The tips at the end are gold tips! Thank you for the amazing tutorial :D
Incredible stuff. Thank you!
Helped me out big time 🙏Gonna give you an extra shoutout in my next devlog.
@@ChapC_Creates thank you! Glad I could help! 😃
Here thanks to his references and it helped me a lot to get rid of pages of unmaintainable code !
I am exactly the 1000th person to like this video 😎. From now on, no one will ever know exactly how many came before them.
Unless the number changes exactly when you hit the like button. ie 1.1K > 1.2K
I watched this video and it's precursor a while ago, and couldn't recall anything from it besides using nodes as states. This weekend I made my own implementation before rewatching these, and I did a surprising amount of things the same way. It's probably a combination of my subconscious, and the fact that there is a natural solution in Godot using nodes. I will detail some cool differences below.
Firstly, I made extensive use of custom component classes, such as a move component that moves a chosen physics body.
Each state has export variables for the components it may affect (dependency injection). If one is left blank it won't error, so there is some flexibility.
I also tried decoupling transition logic from state logic. I made a separate class of state transitions which could be children of states.
That way, the transition logic can be customised for each entity. For example, some entities may have additional states to transition to from idle. The idle state only manages what it needs for an entity to be "idle", not when to change to another state.
Great!
Imma buy those books then
I watched your other state machine videos months ago and I honestly didn't like the implementation. But I'm glad I came back, I didn't realize this was new, and I was actually making a similar input thing for my game.
Thanks for checking it out again! Part of the reason I wanted to revisit the subject for Godot 4 is that, in retrospect, I also felt the original videos were a bit lacking. Still plenty of options in how to make a state machine, but I wanted to make something more comprehensive than before if going for the node-based approach presented here.
I would like to know how do you deal with signals to implement hitboxes and hurboxes. I'm creating the sword attack for the main char I need to implement the hitbox for the sword and the hurtbox for the enemy.
I did it with the same component based approach, I created a hurtbox scene that is just an Area2D with the attribute damage and group "has_damage" and created a hurtbox scene that is just an Area2D with the group "has_health" that holds the max health and current health.
To connect it to the state machine and trigger state changes when I hit an enemy, I had to extend the state machine base class to have also the process_area_signal(area: Area2D) -> void and the state base class to have the matching func process_area_signal(area: Area2D) -> State. And now when I hit the enemy, the original signal _on_area_entered(area: Area2D) calls my enemy's state_machine.process_area_signal(area) and trigger the death state or damage state.
I don't know if this would be the best approach, I'd to hear more about you and how do you deal with signals and state machines
Do you have a discord server?
My approach in the past with signals has been to let the parent object listen and then pass that information down to the state machine, whether with a direct state change or calling a function somewhere, usually because for something like a hurtbox I probably need to manage health, potential s, etc that may need to work outside of the state machine.
I'm afraid I don't have a Discord server. May get around to that one of these days...
at 4:00 I wish you showed the boilerplate code because it would really drive home the use of how to set up this kind of composition. please help thanks
A full example is beyond the scope of the video or this comment, but you'll want to set up a custom class / type like you would any other custom class in Godot, type your component reference in the state machine to that class, and then subclass your components appropriately. Then you'll have things fully typed, have autocomplete available, etc. I know that's a really brief description, but there are a few good resources on TH-cam (and elsewhere) that can help you figure out how to do that more in-depth.
I personally came up with the idea of having shared functions being implemented into the state machine. It's easily accessible, often specific to the very object the machine is attached to.
A component system as mentioned in your video would be the next step for that, especially usefull for re-useable code parts or when it becomes "too much".
The inheritance approach I would stay away from. Not only is it more obfuscating, as you need to go down the hierarchy tree to check up on the function you want to call, it also becomes a real headache if multiple objects want to use the same components/system, but differ widely otherwise. On top of that, generally speaking, inheritance seem to be pretty bad for performance, according to numerous videos on TH-cam. Though I do not know exactly how bad it is and if it holds true in Godot's case (though I very much assume it still is).
those would be symptoms of a poorly set up inheritance structure, not problems with inheritance itself. the indirection / lookups imposed by inheritance is trivial for the purposes of game development
Great explanation! How do you feel about state charts, and more specifically, the state charts extension available on the Godot asset library?
I'm not too familiar with state charts, but from a quick glance at the site, they look interesting, so could be worth trying out. I'm also not very picky about how you handle state management so if it works then go for it!
Hello, I was playing with your state machine Implementation from the first video and I used Godot Resources to inject my movement logic. For example, I have a walk resource that contains some exported vars for walk acceleration, max walking speed, input reading and the logic to apply acceleration and friction. I inject this resource on the fall state, walk state and jump state so the player can move on the X axis during those states. I can record a video explaining it if you want, it's a component driven development I saw here on youtube. When I changed my script to handle the enemy's states, I created a new walk handler for the npc called wander_handler that applies constant Velocity in one direction until a collision happens.
So I have two walk_handlers that extends the Walk resource and I can inject them as I see fit. This way I can create two players with the same base scene and make you of them respond to keyboard wasd and the other to arrows or AI.
P.s. in my state machine Implementation I try to keep the states implementation unique per context. My player and my enemy shares the state machine object and base state. But each one will have a different node for walk or idle. My enemy just walks around and fall, it has no jump. It moves a little wait for a few seconds, move again. If is on wall it changes direction. If I want to use this state graph to other enemy, I can use the movement component to change it's brain. Or if it's going to be super different I prefer to create new states from the base state to avoid coupling
Thanks for sharing the follow up to your last comment! I really like the technique you've developed. Using Resources makes a lot of sense and I like how you've organized everything.
As for the heirarchical states, i made a dash the same way you did, but since my move script changes its animation in process_physics() based on its current velocity.x, the dash animation is overriden after 1 frame with a movement animation. Any way i can ovveride that in the dash script?
Sure, just use the same techniques shown in the video. It'll depend on how you've got it set up, but you could, for instance, move your animation code to a function that dash state overrides.
In a smash bros like brawler would you just have one state machine for attacks and movement because the direction of movement changes what attacks you can do. Each different attack would be its own state and just have jump/fall states return a different up attack state than idle/move?
Hmm, that's tricky. Iirc, there are actions that can be done while moving, so you still might want to have two state machines. Suppose it would depend on exactly how rigid you want to be between moving and acting.
11:32 this game actually looks fkn cool!
Hi, been trying to implement this in my own project but it's a top-down game and I couldn't figure out how you would detect which of the 4 animations (top, down, left and right) to play for each state
Hmm, I'd probably track the orientation in a shared data store that each state can update as appropriate and then name the states in the form "orientation_animation", or something like that. Then, the enter function can be updated so that it plays the animation name given to it, but prepends the orientation to the animation name.
Just one way of doing it.
This tutorial is absolutely fantastic, and I've learned a great deal from it. Thank you very much for sharing your knowledge. I have one observation regarding the "move_component". I noticed that while you've declared types for all parameters and variables, the "move_component" was an exception. Would it be possible to encapsulate these functionalities in a class like "MoveController"? This class could include fundamental methods such as "get_move_direction()", "wants_to_jump()",... In "CharacterBody2D", you might then add a node with a new script titled "PlayerMoveController" that inherits from "MoveController" and overrides certain functions. Within "PlayerMoveController", you could manage controller inputs, and in NPCs, automate certain behaviors. Ultimately, this approach would allow for the specific type declaration for "move_component" using "MoveController", enhancing the robustness and readability of the code.
Yep! You could certainly set this up in such a way as to have typed support all throughout, such as via the method you've mentioned here. I think overall that's a good idea, and it's something I'd normally do. The only reason I didn't do it here is that the move component is so simple, and I find that too much boilerplate can sometimes throw people for a loop.
Hey. I'm having an issue when I have multiple instances of an object, and when one of the state's emit a signal, every instance reacts to it. Any general thoughts why that could be? I recall there being an inspector setting for this, but can't remember where I heard it. Thanks for the video!
Hmm, I'm not 100% certain. Are the signals connected via the editor or via code?
So much great information, thanks for the very good video! I have a question: So I've exported variables, friction, acceleration and speed in the walk state. Now I also want to move horizontally while I am in the jump State. Do I have to copy the export variables from the walk state script and paste them to the jump State script and type the exact numbers in to the inspector. Same also for the Fall State. I also found myself copying the function for moving horizontally from the walk state to the jump and fall state.
Is there a better solution for this? Thanks in advance for the answer!
Hmm, if it's just variables that need to be shared, you could try the data store technique to make that available multiple places. If you have code as well, could be a case to go hierarchical and define a move state that the others inherit from that can share the relevant code with any state that needs it.
@@TheShaggyDevThank you for your help! I'm gonna try that
get error "Invalid call. Nonexist fynction 'init' in base 'Node'"
Whichever node is giving you this error, make sure it has the appropriate script attached.
Would it not be easier and more powerful to just use the AnimationTree state machine with advanced conditions/expressions?
Could give it a go and see how it works! I don't find myself using AnimationTree very often, and what I've presented here is a more generic approach.
@@TheShaggyDev I’m using the animationtree in my current project which is why I was wondering. It’s actually extremely powerful.
Boiling Brain Concepts
It's kind of hard to follow sometimes, it's unclear which script you are working on at times, or how your project looks in the editor, and I am trying to follow along side your website
Apologies! Since this requires some more advanced techniques, I do move a bit more quickly through the topics in order to give an overview of everything. Website is a great choice, but I'd also recommend checking out the sample project to really see how everything fits together.
thanks for reply i’ll check the project notes