Advanced state machine techniques in Godot 4

Here's a look at some more advanced techniques you can implement in your state machine when you need something a bit more complex than the starter state machine I showed in the last video. We'll look at three techniques worth understanding for building out the state machine you need and address a few common pain points people run into when programming a state machine.
Text version with code snippets: shaggydev.com/2023/11/28/godo...
Sample project: github.com/theshaggydev/the-s...
00:00 Dependency injection
02:50 Composition
07:15 Hierarchical state machines
09:25 How to do multiple things at once
10:30 Sharing data between states

Пікірлер: 45

  • @itisjams
    @itisjamsАй бұрын

    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!

  • @BradyHenry
    @BradyHenry6 ай бұрын

    couldn't be more perfect timing on this video

  • @Chaff_Games
    @Chaff_Games6 ай бұрын

    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.

  • @ponderingpermanence8095
    @ponderingpermanence80956 ай бұрын

    Your videos are always a delight, thanks man!

  • @simonscharlachrot7960
    @simonscharlachrot79606 ай бұрын

    clear and concise, thanks!

  • @finestcustard5647
    @finestcustard56476 ай бұрын

    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!

  • @ElementalTJ
    @ElementalTJ6 ай бұрын

    Incredible stuff. Thank you!

  • @Zane_2029
    @Zane_20296 ай бұрын

    Exactly what I was waiting for, right on time too. Was just about to start a Game Dev session.

  • @LuizMoratelli
    @LuizMoratelli6 ай бұрын

    The tips at the end are gold tips! Thank you for the amazing tutorial :D

  • @thaocami657
    @thaocami6576 ай бұрын

    such a great video, thankyou for all the info :O it so much easier to understand now !

  • @Tubulin_
    @Tubulin_5 ай бұрын

    Your videos on state machine are great! Would love further videos delving into the topic of state machines!

  • @starblinky4091
    @starblinky40914 ай бұрын

    Answered some of the remaining questions I had about state machines. Thanks!

  • @dustingarner4620
    @dustingarner46206 ай бұрын

    This is great, thank you!

  • @comradecid
    @comradecid5 ай бұрын

    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

  • @godotgamelab
    @godotgamelab6 ай бұрын

    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!

  • @TheShaggyDev

    @TheShaggyDev

    6 ай бұрын

    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!

  • @godotgamelab

    @godotgamelab

    6 ай бұрын

    @@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!😁

  • @nandomax3

    @nandomax3

    6 ай бұрын

    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

  • @terry-
    @terry-4 ай бұрын

    Great!

  • @GenericInternetter
    @GenericInternetter2 ай бұрын

    11:32 this game actually looks fkn cool!

  • @LucidRhythms
    @LucidRhythms21 күн бұрын

    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.

  • @TheShaggyDev

    @TheShaggyDev

    19 күн бұрын

    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.

  • @papydur
    @papydur6 ай бұрын

    Great explanation! How do you feel about state charts, and more specifically, the state charts extension available on the Godot asset library?

  • @TheShaggyDev

    @TheShaggyDev

    6 ай бұрын

    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!

  • @UhGoomba
    @UhGoomba6 ай бұрын

    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.

  • @TheShaggyDev

    @TheShaggyDev

    6 ай бұрын

    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.

  • @Yoshihara72
    @Yoshihara726 ай бұрын

    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 KZread. 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).

  • @gmailaccountuser352

    @gmailaccountuser352

    5 ай бұрын

    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

  • @serioussammy
    @serioussammy6 күн бұрын

    What if I wanted to use a Animation Tree to blend the animations?

  • @nandomax3
    @nandomax36 ай бұрын

    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

  • @TheShaggyDev

    @TheShaggyDev

    6 ай бұрын

    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.

  • @Max-gm2un
    @Max-gm2un6 ай бұрын

    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!

  • @TheShaggyDev

    @TheShaggyDev

    6 ай бұрын

    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.

  • @Max-gm2un

    @Max-gm2un

    6 ай бұрын

    ​@@TheShaggyDevThank you for your help! I'm gonna try that

  • @doomhardt7680
    @doomhardt76803 ай бұрын

    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

  • @TheShaggyDev

    @TheShaggyDev

    3 ай бұрын

    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.

  • @weouthere9353
    @weouthere93533 ай бұрын

    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!

  • @TheShaggyDev

    @TheShaggyDev

    3 ай бұрын

    Hmm, I'm not 100% certain. Are the signals connected via the editor or via code?

  • @nandomax3
    @nandomax36 ай бұрын

    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?

  • @TheShaggyDev

    @TheShaggyDev

    6 ай бұрын

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

  • @TheOnlyGhxst
    @TheOnlyGhxst4 ай бұрын

    Would it not be easier and more powerful to just use the AnimationTree state machine with advanced conditions/expressions?

  • @TheShaggyDev

    @TheShaggyDev

    4 ай бұрын

    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.

  • @TheOnlyGhxst

    @TheOnlyGhxst

    4 ай бұрын

    @@TheShaggyDev I’m using the animationtree in my current project which is why I was wondering. It’s actually extremely powerful.

  • @fgrtttt
    @fgrtttt3 ай бұрын

    get error "Invalid call. Nonexist fynction 'init' in base 'Node'"

  • @TheShaggyDev

    @TheShaggyDev

    3 ай бұрын

    Whichever node is giving you this error, make sure it has the appropriate script attached.