Starter state machines in Godot 4

Поділитися
Вставка
  • Опубліковано 25 гру 2024

КОМЕНТАРІ • 148

  • @RustoKomuska
    @RustoKomuska Рік тому +66

    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!

  • @jobbingtoaster1502
    @jobbingtoaster1502 Рік тому +56

    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.

  • @Guru2Kid
    @Guru2Kid Рік тому +27

    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!

  • @emdee_
    @emdee_ Рік тому +11

    i just wanted to let you know, thank you for leaving text-based versions in the descriptions. :)

  • @rileylovesee5899
    @rileylovesee5899 4 місяці тому +2

    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!

  • @MTweedC4
    @MTweedC4 8 місяців тому +4

    This is my favorite video on Godot state machines. Love the node-based approach, simple - clean, effective. Thank you Shaggy!

  • @badmonkey91
    @badmonkey91 10 місяців тому +2

    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!

    • @TheShaggyDev
      @TheShaggyDev  10 місяців тому +1

      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.

  • @PeaceInExile
    @PeaceInExile Рік тому +2

    It's been a while since I worked with state machines, so I really appreciated this video as a refresher.

  • @Portponky
    @Portponky Рік тому +8

    Nice to see this topic covered again for Godot 4.

  • @arcade_mntra
    @arcade_mntra Рік тому +5

    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.

  • @morneerasmus1789
    @morneerasmus1789 9 місяців тому

    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 :)

  • @FuzzballStudios
    @FuzzballStudios Рік тому +4

    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.

  • @wedge_one
    @wedge_one Рік тому

    this is the best video about node base state mechine in Godot. the examples helps A TON! ty for the video!

  • @RetroBright262
    @RetroBright262 7 місяців тому +5

    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.

    • @TheShaggyDev
      @TheShaggyDev  7 місяців тому +3

      Oh I like that idea! Signals would give you a good bit of flexibility, as you've mentioned.

  • @hamsu7453
    @hamsu7453 Рік тому +1

    Keep it up man, waiting on the next more advanced FSM tutorial!

  • @DavidReidChannel
    @DavidReidChannel 3 місяці тому +1

    Shaggy Dev. This was incredibly useful. Thanks for sharing.

  • @Brokencircuitboard
    @Brokencircuitboard 5 місяців тому +2

    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 😆

  • @N7sensei
    @N7sensei 6 днів тому

    Thank you, sir!

  • @jules_________
    @jules_________ Рік тому

    How much was i waiting for this, thanks !

  • @s_o0om
    @s_o0om 3 місяці тому

    this is quite genuinely better than sliced bread. thank you so much for this

  • @Zane_2029
    @Zane_2029 Рік тому

    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

  • @hamsu7453
    @hamsu7453 Рік тому

    Yes please more in depth one. Keep it up!

  • @lousyllamma986
    @lousyllamma986 2 місяці тому +1

    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.

  • @MrBoingus
    @MrBoingus Рік тому +2

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

  • @nandomax3
    @nandomax3 Рік тому

    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

  • @kron520
    @kron520 Рік тому +1

    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.

  • @Redvirex
    @Redvirex Рік тому

    thanks for the video, so useful, waiting for the next

  • @shindig9000
    @shindig9000 Рік тому

    I can't wait for the next video!

  • @addmix
    @addmix Рік тому

    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.

  • @crebafurros
    @crebafurros Рік тому

    No way, I was just watching your old videos on this topic because I started studying finite state machines, what a coincidence lmao

  • @ChrisSwafford1
    @ChrisSwafford1 Рік тому

    Thank you!

  • @NexusBaum
    @NexusBaum 3 місяці тому

    good stuff!

  • @luisces
    @luisces Рік тому +2

    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!

    • @melpeslier
      @melpeslier Рік тому

      It's because you don't try by yourself, videos are great, yeah, but ONLY after you've struggled a lot

  • @terry-
    @terry- 11 місяців тому +1

    Great!

  • @wick3dwick
    @wick3dwick Рік тому

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

  • @Max_prez555
    @Max_prez555 Рік тому

    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!

    • @TheShaggyDev
      @TheShaggyDev  Рік тому +1

      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.

  • @melpeslier
    @melpeslier Рік тому +1

    Good stuff 🔥
    Don't forget to try your own things without looking at vids or else you won't progress guys 😉

  • @wesc6755
    @wesc6755 7 місяців тому +5

    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.

  • @thrustwizard9082
    @thrustwizard9082 Рік тому

    for simpler sate machines (like your turret) i like to use a setter to handle changing state.

  • @a1534-d7k
    @a1534-d7k Рік тому

    would love an in depth video on hierarchical state machines in godot 4

  • @zombiegamer8243
    @zombiegamer8243 2 місяці тому

    i think the node based approach might be better in some situations as if we wanted to add and remove possible states for example

  • @P1agueDoc
    @P1agueDoc Рік тому +1

    Please please pl3ase do more on state machines this helelped so damn much

  • @Skiggles
    @Skiggles 4 місяці тому +1

    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.

  • @Yoshihara72
    @Yoshihara72 Рік тому

    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.

  • @rhinoromp5164
    @rhinoromp5164 Рік тому

    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.

  • @starblinky4091
    @starblinky4091 10 місяців тому +1

    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.

    • @TheShaggyDev
      @TheShaggyDev  10 місяців тому +1

      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.

  • @SameeraD-v2f
    @SameeraD-v2f 3 місяці тому

    It is so excited ❤
    But how we practiced can you please suggest

  • @jacksonday6737
    @jacksonday6737 2 місяці тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  2 місяці тому

      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

  • @TheOnlyRandomChannel
    @TheOnlyRandomChannel Рік тому +1

    How would you handle concurrent states? For example if the player is attacking mid jump or while moving?

    • @TheShaggyDev
      @TheShaggyDev  Рік тому

      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.

  • @alfredogodoy6854
    @alfredogodoy6854 Рік тому

    I met you thanks the introduction to Utility AI video. I would like to see a video about its implementation in Godot.

  • @thevictor7851
    @thevictor7851 9 днів тому

    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

  • @VenomousIncorporated
    @VenomousIncorporated Рік тому

    It would be interesting to see how you handle various different types of Entities (Player, NPC, Object)

  • @HueStudios-i5e
    @HueStudios-i5e 3 місяці тому

    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.

    • @TheShaggyDev
      @TheShaggyDev  3 місяці тому

      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.

  • @SoporteSys16
    @SoporteSys16 Рік тому

    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.

  • @matthiash5428
    @matthiash5428 10 місяців тому

    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.

    • @TheShaggyDev
      @TheShaggyDev  10 місяців тому

      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.

  • @disastideas5209
    @disastideas5209 6 місяців тому

    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

    • @disastideas5209
      @disastideas5209 6 місяців тому

      I'm assuming it's just preference

    • @TheShaggyDev
      @TheShaggyDev  6 місяців тому

      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.

  • @AleczanderSmith
    @AleczanderSmith Рік тому +2

    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()`

    • @TheShaggyDev
      @TheShaggyDev  Рік тому +1

      Make sure you've set the starting state on your state machine. That should be an exported node you can edit from the inspector.

    • @Chase_Is
      @Chase_Is Рік тому

      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

    • @TheShaggyDev
      @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.

    • @Chase_Is
      @Chase_Is Рік тому

      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

    • @Chase_Is
      @Chase_Is Рік тому +1

      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

  • @tristangillis7365
    @tristangillis7365 Рік тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  Рік тому +1

      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.

    • @tristangillis7365
      @tristangillis7365 Рік тому

      @@TheShaggyDev
      All good, I'll keep playing around with it. Thanks for the reply!

  • @googleyoutubechannel8554
    @googleyoutubechannel8554 10 місяців тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  10 місяців тому

      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.

  • @TheLucas9d
    @TheLucas9d 3 місяці тому

    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

  • @drage2662
    @drage2662 11 місяців тому

    isn't class_name supposed to be under extends in scripts? 5:57

    • @TheShaggyDev
      @TheShaggyDev  11 місяців тому

      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"

  • @hidingdissident
    @hidingdissident 6 місяців тому

    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

    • @TheShaggyDev
      @TheShaggyDev  6 місяців тому

      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.

  • @jo-wx8ng
    @jo-wx8ng 7 місяців тому

    I'm confused 5:45. where does this class name thing go?

    • @TheShaggyDev
      @TheShaggyDev  7 місяців тому +1

      That should go in your script holding the base state implementation (see "state.gd" in the sample project)

  • @santoshgujar5237
    @santoshgujar5237 8 місяців тому

    ✨🙏🏼✨

  • @maykefernandesdossantos7374

    could owner property simplify the code so that we dont have to pass the parent down?

    • @TheShaggyDev
      @TheShaggyDev  Рік тому

      Sure, that would work just fine for something like what's shown in the video.

  • @MarcelArtsCW
    @MarcelArtsCW 7 місяців тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  7 місяців тому

      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.

  • @mudinlange
    @mudinlange 10 місяців тому

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

    • @TheShaggyDev
      @TheShaggyDev  10 місяців тому

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

  • @CyonixOfficial
    @CyonixOfficial 5 місяців тому +2

    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)

  • @vettie
    @vettie 7 місяців тому

    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.

  • @HenrikJansson-r9g
    @HenrikJansson-r9g 3 місяці тому

    Great content! But how come I can't download ZIP for this project in Github? It's so much easier to understand that way.

    • @TheShaggyDev
      @TheShaggyDev  3 місяці тому

      Go to the repo root and you can download everything as a zip: github.com/theshaggydev/the-shaggy-dev-projects/tree/main

  • @zacklewan4183
    @zacklewan4183 Рік тому

    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#?

    • @melpeslier
      @melpeslier Рік тому +1

      public void Init(Player parent)
      {
      foreach (Node child in GetChildren())
      {
      child.SetParent(parent);
      }
      }

    • @zacklewan4183
      @zacklewan4183 Рік тому

      @mel-du-studio-coco thanks! Though, i don't think SetParent exists (I get an error saying it doesnt). What would be the alternative?

    • @melpeslier
      @melpeslier Рік тому

      here the 'set parent would be a custom function that you've made that assign the property 'parent' of your state script.

    • @melpeslier
      @melpeslier Рік тому

      child.parent = parent
      @@zacklewan4183

  • @Dkerza
    @Dkerza 5 місяців тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  5 місяців тому +1

      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.

  • @davisnoah347
    @davisnoah347 5 місяців тому

    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.

    • @TheShaggyDev
      @TheShaggyDev  5 місяців тому

      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.

  • @MrBoingus
    @MrBoingus 4 місяці тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  4 місяці тому +1

      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.

    • @MrBoingus
      @MrBoingus 4 місяці тому

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

    • @TheShaggyDev
      @TheShaggyDev  4 місяці тому +1

      @@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 😊

    • @MrBoingus
      @MrBoingus 4 місяці тому

      @@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?

    • @MrBoingus
      @MrBoingus 4 місяці тому

      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

  • @JordanTolev
    @JordanTolev Рік тому

    I love you platonically

  • @Hades200082
    @Hades200082 Рік тому

    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

    • @TheShaggyDev
      @TheShaggyDev  Рік тому

      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.

  • @jo-wx8ng
    @jo-wx8ng 7 місяців тому

    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?

    • @TheShaggyDev
      @TheShaggyDev  7 місяців тому +1

      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)

  • @Chase_Is
    @Chase_Is Рік тому

    Hey, if anyone could help, when I call for the state machine to initiate itself I receive and null instance. Why is this so?

  • @ben112234455
    @ben112234455 2 місяці тому

    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

    • @TheShaggyDev
      @TheShaggyDev  2 місяці тому

      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"

    • @ben112234455
      @ben112234455 2 місяці тому

      @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
      @TheShaggyDev  2 місяці тому

      @@ben112234455 that's correct. If you want to keep troubleshooting, what was the solution you found?

    • @WebCamCartmell
      @WebCamCartmell 2 місяці тому

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

    • @WebCamCartmell
      @WebCamCartmell 2 місяці тому

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

  • @mattseaton5832
    @mattseaton5832 Рік тому

    Ok Fine. But why not just use the statemachine already implemented in an animationtree?

  • @davariusaz
    @davariusaz 5 місяців тому +1

    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.

    • @G4M5T3R
      @G4M5T3R 2 місяці тому +1

      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.

    • @noneofyourbuisness2539
      @noneofyourbuisness2539 2 місяці тому

      Even easier just return the blank base state that does nothing via the export variables

  • @pogrammer
    @pogrammer Місяць тому

    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.

  • @2archarry
    @2archarry 7 місяців тому

    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.

  • @emmanuelgbenebichie1527
    @emmanuelgbenebichie1527 День тому

    I'm the only one still finding this difficult to understand 😪

  • @salmonbamminfish2925
    @salmonbamminfish2925 4 місяці тому

    how in the world do you download crap off of github

    • @TheShaggyDev
      @TheShaggyDev  4 місяці тому +1

      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.

    • @salmonbamminfish2925
      @salmonbamminfish2925 4 місяці тому

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

    • @TheShaggyDev
      @TheShaggyDev  4 місяці тому +1

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

    • @salmonbamminfish2925
      @salmonbamminfish2925 4 місяці тому +1

      @@TheShaggyDevthank you so much. I am very blind and missed the extends node inside the base state class. Appreciate your help

    • @TheShaggyDev
      @TheShaggyDev  4 місяці тому +1

      @@salmonbamminfish2925 Glad you got it sorted out!

  • @PunCala
    @PunCala Рік тому +1

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

    • @PeaceInExile
      @PeaceInExile Рік тому

      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.

    • @PunCala
      @PunCala Рік тому

      @@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?

    • @PeaceInExile
      @PeaceInExile Рік тому +1

      @@PunCala I haven’t come across a reason to use that parameter yet. For now I’ve been ignoring it

  • @darthnegativehunter8659
    @darthnegativehunter8659 Рік тому +2

    you should NOT have state machines in gdscript for a production build.

    • @darthnegativehunter8659
      @darthnegativehunter8659 Рік тому +1

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

  • @soundrogue4472
    @soundrogue4472 Рік тому +1

    Oh yeah, so "simple" that my code isn't working.