Video summary
LimboAI State Machine Tutorial and Guide for Godot 4 - Beginner Friendly - Part 2/2
Main summary
Key takeaways
Main ideas / lessons
- The video demonstrates how to implement a Limbo AI Event-Based Hierarchical State Machine (HSM) in Godot 4.3, and how to connect it to a player character.
- Core pattern:
- Create an HSM node inside the player scene.
- Create state nodes (idle, move, jump, fall, attack, air attack, crouch).
- Attach scripts to each state implementing
enterandupdate(as needed). - Add signals/transitions in the player script so states can move between each other.
- Dispatch signals from state logic based on inputs, physics (e.g.,
velocity/is_on_floor()), and animation events.
- The state machine drives animation and high-level behavior, while basic movement/physics can remain in the agent/player code. The tutorial sometimes uses approaches that aren’t best practice, but favors clarity.
Step-by-step methodology
1) Set up the state machine in the player scene
- Open the player scene.
- Select the Root node (Player).
- Add a Limbo AI HSM node:
- Add child node → search limbo → add limbo HSM (event-based hierarchical state machine).
- Add state nodes under the HSM:
- Right-click the HSM → search limbo State → create/duplicate until you have 7 states.
- Rename them:
idle,move,jump,fall,attack,air_attack,crouch
- Note:
- These states won’t do anything yet because they have no scripts/code attached, and the player script doesn’t yet know about the state machine.
2) Create and configure the idle animation (for the idle state)
- Add an AnimationPlayer to the player node (if not already present).
- Place it at the top (preference).
- Create a new animation:
- Name:
idle
- Name:
- Configure frames:
- The tutorial’s sprite sheet has 8 frames.
- Enable looping (Loop enabled).
- Ensure all 8 frames are included in the animation timeline.
- Test play to confirm the idle animation loops correctly.
3) Update the player script to reference the state machine and initialize it
In the player script:
- Add a state machine variable exported to the Inspector:
export var state_machine : <HSM node type>
- Add references to state nodes (assigned via drag/drop in the Inspector):
idle_state(and similar for other states)
- Initialize the state machine in
ready():- Call an internal function (e.g.,
finalize_state_machine/ “initialize state machine”).
- Call an internal function (e.g.,
- Initialization tasks inside that function:
- Set default/initial state:
- initial state =
idle_state
- initial state =
- Call
initializeon the state machine (withselfas required by the tutorial). - Activate it:
state_machine.set_active(true)
- Set default/initial state:
- Attach the first state script:
- Right-click the
idlestate node → Attach Script - Place scripts in a folder such as:
scripts/agents/player/states/
- Example script name:
idle.gd
- Right-click the
4) Implement idle state behavior (animation + transitions to move)
Idle state script:
- Export references:
export var animation_player : AnimationPlayerexport var animation_name : String(set to"idle"in Inspector)
- Implement
enter():- Play the idle animation using the configured AnimationPlayer + animation name.
- Key idea:
enter()runs only once when the state is activated (great for starting animations).
- Transition logic to move:
- Implement
update(delta)(notprocess) so it runs only while the state is active. - In each frame of
idle:- if
movement_input != Vector2.ZERO - dispatch signal
to_movefrom the state machine root to transition tomove.
- if
- Implement
Player/agent responsibilities (movement input):
- Add movement input variable:
movement_input : Vector2
- In
physics_process:movement_input = Input.get_vector(<left>, <right>, <up>, <down>)
- Configure Input Map actions in Project Settings:
- left/right/up/down (examples:
A/D,W/Up,S/Down)
- left/right/up/down (examples:
5) Implement move state (movement application, animation, and transitions back)
Move state setup:
- Assign the AnimationPlayer reference and create a
moveanimation (loop it).
Move state logic:
- Transition back to
idle:- In
update(delta), ifmovement_input == Vector2.ZERO:- dispatch
to_idle
- dispatch
- In
Movement/velocity:
- The tutorial uses movement logic in the agent/player code:
- Add
apply_movement(delta)in the agent script - Use
movement_input+move_speedto update velocity
- Add
- The move state triggers/apply this logic each frame (the tutorial applies it directly from states for simplicity).
Sprite direction / facing:
- Add a function in player/agent script:
update_sprite_direction()(or similar)
- Flip sprite based on X input direction (ensure the
spritereference exists). - The tutorial uses:
unready VAR sprite : Sprite3D(assigned in Inspector)
6) Add jump transitions and implement jump + fall logic
Transitions:
- From
idletojumponto_jump - From
movetojumponto_jump - The tutorial also mentions an alternative:
- “any state can go to jump,” but it’s not fully optimized.
Input checking:
- Add Input Map action:
jump(example: Space)
- Add player function:
check_jump_input()
- When jump is pressed:
- dispatch
to_jump(subject to conditions later)
- dispatch
- Call
check_jump_input()from both:idle.update(...)move.update(...)
Jump state:
- Configure a
jumpanimation. - Implement
enter():- Set jump velocity once:
velocity.y = jump_velocity
- Set jump velocity once:
- Transition to falling:
- Add
fallanimation and transition when falling. - In
jump.update(delta), if:velocity.y < 0AND NOTis_on_floor()
- dispatch
to_fall
- Add
Landing logic (fallback transitions):
- In
fall.update(delta):- if
is_on_floor():- if
movement_input == Vector2.ZERO→ dispatchto_idle - else → dispatch
to_move
- if
- if
- Also apply movement while jumping/falling by calling
apply_movement(delta)from those states as needed (the tutorial repeats this so you can move during jump/fall).
7) Add crouch transitions and implement crouch behavior
Transitions:
- Add transition:
idle→crouchwhento_crouchis dispatched.
Crouch input:
- Add Input Map action:
crouch(example:C)
- In
idle.update(delta):- call something like
check_crouch_input() - if crouch pressed:
- dispatch
to_crouch
- dispatch
- call something like
Animations:
- Add
crouchanimation and AnimationPlayer reference.
Crouch exit:
- In
crouch.update(delta):- if crouch input is released:
- dispatch back to
idle
- dispatch back to
- if crouch input is released:
Important issue noted by the tutorial:
- Without an exit transition, the character can get stuck in crouch.
8) Add attack and air_attack transitions and implement animation/event resets
Animations and state setup:
- Create/assign:
attack(ground)air_attack(variant with feet hovering)
- Ensure each state has AnimationPlayer reference + animation name set correctly.
Transitions (simple rule from the tutorial):
- Attack from:
idle(ground) andjump(air), depending on floor contact.
- Add transitions:
idle→attackonto_attackjump→air_attackonto_air_attack
- Note/fix mentioned:
- missing transitions can prevent reaching the intended state (the tutorial highlights a sloppy copy/paste bug).
Attack input:
- Add Input Map action:
attack(example:Ctrl)
- Implement player function
check_attack_input():- If on floor and attack pressed:
- dispatch
to_attack
- dispatch
- If NOT on floor and attack pressed:
- dispatch
to_air_attack
- dispatch
- If on floor and attack pressed:
Animation reset / state return after attack:
- Problem:
- attack animations may “never really reset” and the state never returns automatically.
- Fix using AnimationPlayer signal:
- Connect AnimationPlayer’s
animation_finishedsignal to a player function (e.g.,on_animation_player_animation_finished).
- Connect AnimationPlayer’s
- In that function:
- if
animation_name == "attack":- dispatch state machine to
idle
- dispatch state machine to
- if
animation_name == "air_attack":- dispatch to
fall
- dispatch to
- if
What state functions mean (as emphasized)
enter():- runs once when the state becomes active (used for one-time setup like starting animations or applying jump impulse).
update(delta):- runs only while the state is active (used for per-frame decisions like transitions based on input/physics; the tutorial sometimes also applies movement here, although it’s noted as not best practice).
Speakers / sources featured
- Speaker: The video narrator/instructor (unnamed)
- Source context: Teaching Limbo AI State Machine in Godot 4.3 across Part 2/2.
Rate this summary
Your feedback will help improve summaries.
Improve this summary
Reprocess with a stronger model when the summary feels incomplete or inaccurate.
Translate summary in another language
Ask questions to this video
Chat for follow-up questions, clarifications, and source-backed answers.