Finite State Machines in Godot | Godot Starter Kit FSM

Поделиться
HTML-код
  • Опубликовано: 24 ноя 2024

Комментарии • 62

  • @jacknight3690
    @jacknight3690 День назад +1

    Good you fucking explained what inherited means and how to do it, im sooo fucking glad

  • @kostanislaw
    @kostanislaw 10 месяцев назад +17

    Лучший урок по стейтам, что я видел. Не только дал удобную ФСМ, но ещё и очень просто объяснил как всё это работает и зачем нужна каждая строчка. Блин, если бы все на ютубе объясняли как ты - я бы уже закончил свою игру. Спасибо!

  • @philldev
    @philldev 11 месяцев назад +28

    This is a very useful video for all beginners, not just godot users! It explains exactly what a FSM is and how it should work, not to mention it is well edited and easy to understand. Good job, keep up the good work :)

    • @ForlornU
      @ForlornU  11 месяцев назад +3

      Thank you, means a lot coming from a fellow dev!

  • @locke_d
    @locke_d 11 месяцев назад +10

    tysm for this tutorial, ngl the code here is like identical to a tutorial about the same subject from Bitlytic (not sure if that's intentional or a happy accident) but like, you actually explain it in a thorough and easy to understand way? Bitlytic skims over so much important info for beginners but you hit the nail right on the head with the explanations, super comprehensive and easy to follow, tysm again king ily

    • @athosdev4181
      @athosdev4181 Месяц назад

      they're implementing the same thing, its all finite state machine in its core, so the logic will look really similar if not the same.

  • @NikoDuong
    @NikoDuong 11 месяцев назад +8

    You are a godsend! Explanations were short concise and easily understandable.
    Thank you from the bottom of my heart! I can't wait for more!

    • @ForlornU
      @ForlornU  11 месяцев назад +1

      Thank you for the kind words. More videos are coming!

  • @kloa4219
    @kloa4219 10 месяцев назад +6

    I'm nearly done with porting this to Godot 3, thank you for explaining it clearly.

    • @kloa4219
      @kloa4219 10 месяцев назад +1

      Finite State Machine
      extends Node
      class_name FiniteStateMachine
      var states : Dictionary = {}
      export var initial_state = NodePath()
      onready var initstate:State = get_node(initial_state)
      var current_state:State
      var change_state:State
      func _ready():
      for child in self.get_children():
      if child is State:
      states[child.name.to_lower()] = child
      child.connect("state_transition", self,"change_state")
      if initial_state:
      initstate.Enter()
      current_state = initstate
      func change_state(source_state:State, new_state_name:String):
      #redundancy checks
      if source_state != current_state:
      print("Invalid change_state trying from: " + source_state.name + "but current in: " + current_state.name)
      return
      var new_state = states.get(new_state_name.to_lower())
      if !new_state:
      print("New state is empty")
      return
      #only relevant lines
      if current_state:
      current_state.Exit()
      new_state.Enter()
      current_state =new_state
      func force_change_state(new_state:State):
      var newState = states.get(new_state.name.to_lower())
      if !newState:
      print(str(new_state) + " does not exist in the dictionary of states")
      return
      if current_state ==newState:
      print("State is same, aborting")
      return
      if current_state:
      current_state.call("Exit")
      current_state=newState
      newState.Enter()
      func _process(delta):
      if current_state:
      current_state.Update(delta)
      func _physics_process(delta):
      if current_state:
      current_state.Update(delta)

    • @kloa4219
      @kloa4219 10 месяцев назад

      Player_Idle State
      extends State
      class_name Player_Idle
      export var sprite = NodePath()
      onready var _sprite :AnimatedSprite = get_node(sprite)
      #gets FSM node
      onready var fsm = get_parent()
      #onready var fsm = $".."
      onready var moving = $"../Moving"
      func Enter():
      #_sprite.play("Idle")
      pass
      func Exit():
      pass
      func Update(_delta:float):
      if (Input.get_vector("move_left","move_right","move_forward","move_backward")):
      print("moving")
      #Transition to move state
      fsm.change_state(self, "Moving")
      pass
      if (Input.is_action_just_pressed("attack")):
      #transition to attack state
      pass
      pass

    • @kloa4219
      @kloa4219 10 месяцев назад

      extends Node
      class_name State
      signal state_transition
      func Enter():
      pass
      func Exit():
      pass
      func Update(_delta:float):
      pass
      func Physics_Update(_delta:float):
      pass

  • @curtiss5781
    @curtiss5781 9 месяцев назад +1

    I had a project where I tried a sort of state machine but used timed animations that would trigger follow up states. I ran into issues when trying to do a forced state while animations were still running. Im pretty sure a more defined approach like what you have here would have sorted out my issues, being able to end animation delegates in the current state Exit method before killing the object. Cool explanation, thanks.

  • @fuzzy-02
    @fuzzy-02 4 месяца назад +2

    That punch animation was personal

  • @Rawbherb
    @Rawbherb 2 месяца назад

    This looks like a very organized way to do it. I just throw all of the states in a switch function in my player’s script, and each state gets its own function, and then each state’s function has logic for the other states it can switch to… I like this idea though!

    • @ForlornU
      @ForlornU  Месяц назад

      Hey as long as it works that's what matters!

  • @offlinemoe
    @offlinemoe 5 месяцев назад

    Just found your channel and I fell in love with it

  • @hensola
    @hensola 6 месяцев назад

    Lovely intro on how FSM work, as well as separating them all out to a manager function. I believe this is how Godot is meant to be programmed.

  • @cheesymcnuggets
    @cheesymcnuggets 10 месяцев назад +2

    I don't think I actually need a state machine but i want to learn them, this is like the third video I've watched on them and they haven't become any less intimidating. Question about your force state function, how exactly can it break your game? Aren't exit functions meant to prevent the state machine from breaking or have I misunderstood their purpose? Oh wait the problem is with decentralised state machines, right? Since each state is only accounting for it's own transitions and trying to transition to something it doesn't know how to could break things? I don't know...

    • @kloa4219
      @kloa4219 10 месяцев назад

      Think of state machines as applying a script to each game mechanic. It isn't important for small projects but it makes doing big projects like RPGs or fighting games easier.

    • @ForlornU
      @ForlornU  9 месяцев назад +1

      "Break your game" was me being a bit dramatic. Creating a system of transitions only to then override them with force can lead to unexpected behaviour I guess. I don't want to make a tutorial where I use a 'force-change' function to ignore what I am trying to teach in the video

  • @PaintedCz
    @PaintedCz 11 месяцев назад +2

    This is fantastic! Thank you so much!

  • @Altaryum
    @Altaryum 6 месяцев назад

    Thanks for this very comprehensive tutorial about FSM. 🤗

  • @Lily-kv3rb
    @Lily-kv3rb 6 месяцев назад +1

    I've been watching through a couple of different videos after finishing my player movement system in my first game and decided to switch it over to a state machine, since I plan on adding even more movement mechanics later on and I want to make it easier on myself. This is the first video I've found that explains things in such detail, so thank you! However, in every video I've watched and tried to follow along, I keep getting stuck on specific tidbits that I can't seem to find an answer to either in the video, or on specific searches on Reddit/Google/Etc. Where would be the best resource for figuring out solutions to problems like "In my Finite State Machine script, there are 'Could not parse global class "State" from "res"//Scripts/PlayerState.gd" over every mention of the variable 'initial_state'. How do I fix this?". I want to find a community or resource where I can easily look up these errors and find out why its not working. And if the reason I can't figure this out is due to a lack of very basic knowledge of GDScript, where should I start learning that basic knowledge?

  • @PaperMouseGames
    @PaperMouseGames 10 месяцев назад

    Fantastic video! Very high quality and helpful, thank you!

  • @fuzzy-02
    @fuzzy-02 4 месяца назад

    Any tips on how to combine this with composition (stuff like making components and composing entities from them, like VelocityComponent, HealthComponent, WanderAroundComponent, etc)

  • @vladyerus
    @vladyerus 10 месяцев назад +1

    This video helped me more than most to figure out state machines. thank you. Do you know if this code allows for switching scenes?
    For example i have a state called Driving (my character goes invisible, stops processing, etc) and i take control of another characterbody2d which has its own set of states .

    • @ForlornU
      @ForlornU  10 месяцев назад +1

      Absolutely. An interaction script activates the vehicle and tells the fsm to transition to driving state which 'deactivates' the player. A player state should not be responsible for anything outsider the player i think 👍

  • @cioelle
    @cioelle 4 месяца назад

    amazing video, but i feel it's definitely important to show and explain how to use state_transition and explain what it does, and how it connects the scripts. great otherwise though, i needed someone to explain FSM to me like i'm 5 lmao

    • @ForlornU
      @ForlornU  4 месяца назад +1

      Noted, sorry I didn't explain that more clearly! Glad it was still helpful :)

  • @fuzzy-02
    @fuzzy-02 4 месяца назад

    Is this the same as Finite State Automata?
    Where you have a Deterministic Finite Automaton, DFA, a Non Deterministic one, NFA, an Epsion Non Deterministic one, e-NFA, and you work on reducing whatever automata you have into a minimal deterministic one?
    I took this as part of an introductory course to compilers and it seems awfully similar

  • @panwladca8800
    @panwladca8800 6 месяцев назад

    Thank you for your hard work 😊

  • @ykyjohn
    @ykyjohn 6 месяцев назад +1

    Where/When the state_transition is emitted?

  • @markaven5249
    @markaven5249 11 месяцев назад +1

    I don't know why but state machines seem so much more difficult and less straightforward than in C, C++, or C#. It must be the whole dynamic programming thing.
    In C like languages, I'd just create a state and subState enum, subState would have Init, Run, End and state would have animation names, then just create one long script for everything. Signals are just Events and Callbacks but they call them signals. I guess these days this isn't a modern style of programming, but I'd have as few scripts as possible as well.

    • @kloa4219
      @kloa4219 10 месяцев назад +2

      You can do it with enums in Godot. It just feels messy in comparison to the node method

  • @1tsKayne
    @1tsKayne 8 месяцев назад

    i dont know how i should transition the state for my enemy. so it detects when the player entered his territory and then it should switch to chase state. What do I have to put in there?
    # In the Idle State:
    func _on_view_area_body_entered(body):
    if body.is_in_group("Player"):
    FiniteStateMachine.change_state(State, "BaseNPCChaseState")

    doesnt work

  • @kloa4219
    @kloa4219 10 месяцев назад +1

    How did you animate your video btw?

    • @ForlornU
      @ForlornU  9 месяцев назад +3

      I use Davinci resolve for editing, the coding animations are done in good 'ol powerpoint!

  • @SiddhantaGhosh-q1o
    @SiddhantaGhosh-q1o 2 месяца назад

    which code is connected to which?

  • @boxboy9000-f7r
    @boxboy9000-f7r 4 месяца назад

    it keeps saying could not find type state in the current scope!

  • @DariusK-f5e
    @DariusK-f5e 2 месяца назад

    :( State_Machine.gd:16 - Parse Error: Cannot call non-static function "Enter()" on the class "State" directly. Make an instance instead.

    • @ForlornU
      @ForlornU  2 месяца назад

      It's telling you to call the 'Enter()' function on one of the states, not the 'State' superclass itself. Are you trying to make new states?

    • @pand2aren
      @pand2aren 2 месяца назад

      @@ForlornU sorry for lack of context in my comment, it throws me error in 2:58 part in statemachine main script in func _ready > initial.state.Enter() i guess i missed something.

  • @Konslufius
    @Konslufius 4 месяца назад

    I'm sry I understand how a statemachine works in theory, but I can not make sense of this line:
    child.state_transition.connect(change_state)

  • @SiddhantaGhosh-q1o
    @SiddhantaGhosh-q1o 2 месяца назад

    so i am using godot 4.2 can it work
    platformer

    • @ForlornU
      @ForlornU  2 месяца назад

      Grab the 1.4 release for Godot 4.2. Yes you can make it into a platformer, just add gravity basically :)

    • @SiddhantaGhosh-q1o
      @SiddhantaGhosh-q1o 2 месяца назад

      when i downlorded it i shows godot 4.3

    • @ForlornU
      @ForlornU  2 месяца назад

      This is 4.2 Compatible, but I would also suggest just upgrading :) : github.com/ForlornU/TopdownStarter/tree/1.4

  • @HurricaneSA
    @HurricaneSA 10 месяцев назад +20

    Please for the love of my sanity can you choose a notation and stick with it? Changing between snake and camel notation randomly is making my brain hurt.

    • @ForlornU
      @ForlornU  9 месяцев назад +11

      Indeed it was getting out of hand, resolved in latest version!

    • @MTweedC4
      @MTweedC4 7 месяцев назад

      😂 good sport

    • @user-db2uj9vc7s
      @user-db2uj9vc7s 10 дней назад

      An standard naming convention is very good for team work, but for a solo small project it really is not that deep

  • @GenericInternetter
    @GenericInternetter 10 месяцев назад

    "press enter to leave"
    huh?

    • @ForlornU
      @ForlornU  10 месяцев назад

      That does sound strange when you point it out 😅

  • @truenincillo805
    @truenincillo805 9 месяцев назад

    Tutorial swim in 2d platform game godot 4 please😣

  • @PocketDeerBoy
    @PocketDeerBoy 6 месяцев назад +2

    I feel like you sort of skipped over the part where you explain how states communicate with each other? I looked through the github to try to understand the code better and there's this line from the Idle state:
    state_transition.emit(self, "Moving")
    that was never explained. I'm sorry, I'm very new to coding and I wanted to figure out state machines, but I'm not sure how this piece of code works and how it's picked up by other codes. My guy is still not walking

    • @theseangle
      @theseangle 5 месяцев назад

      state_transition is the signal that is defined in the IdleState's script. This line emits the signal of a transition from IdleState to MovingState to the state machine class. The state machine has `current_state.state_transition.connect(handle_transition)`. It makes the FSM subscribe to the transition event that is emitted from the current state. On that event, it calls the `handle_transition` function which is defined in the FSM. It has two arguments: previous_state and new_state. Both of them correspond to the two arguments `self` and `Moving` respectively from the IdleState's script.
      "Moving" is the name of the MovingState node, which plays as the accessor for the MovingState. It's used in the `handle_transition` function to get the state node by the string, like `current_state = get_children()[new_state]`

  • @bernardbrookshire7171
    @bernardbrookshire7171 5 месяцев назад +1

    not helping

  • @bsdrago
    @bsdrago 10 месяцев назад

    what about unity? =)

  • @templeoftaste320
    @templeoftaste320 5 месяцев назад +1

    Useless, you left out the most important part about how to actually trigger a state transition from the idle state class