Godot Version
Godot 4.2.2
Question
Hello, I work on my game’s movement and i wanted to make it modular from beginning, so i try implementing a state machine. I know it will be long but i will give all the details of my code( at least the useful one).
Physics_Component.gd
class_name PhysicsComponent extends PhysicsInterface
func accelerate(parent: CharacterBody2D, delta: float) -> void:
parent.velocity.x = move_toward(velocity.x, direction * speed, speed * acceleration)
parent.velocity.normalized()
func decelerate(parent: CharacterBody2D, delta: float) -> void:
parent.velocity.x = move_toward(velocity.x, 0, speed * friction)
parent.velocity.normalized()
func jump(parent: CharacterBody2D) -> void:
parent.velocity.y = move_toward(velocity.y, -jump_force, jump_force * jump_scale)
parent.velocity.normalized()
func apply_gravity(parent: CharacterBody2D, delta: float) -> void:
parent.velocity.y += gravity * fall_scale * delta
parent.velocity.normalized()
func move(parent: CharacterBody2D) -> void:
parent.move_and_slide()
func manage_movement(parent: CharacterBody2D, delta: float) ->void:
direction = Input.get_axis("move_left", "move_right")
if direction:
accelerate(parent, delta)
else:
decelerate(parent, delta)
if !is_on_floor():
apply_gravity(parent, delta)
#print(direction)
move(parent)
func check_movement(event: InputEvent) -> bool:
if event.is_action_pressed("move_left") or event.is_action_pressed("move_right"):
return true
return false
func check_jump(parent: CharacterBody2D, event: InputEvent) -> bool:
if event.is_action_pressed("jump") and parent.is_on_floor():
return true
return false
func get_direction() -> int:
return direction
This a component that does all the physics related calculations.
State_Machine.gd
extends Node
@export var initial_state: State
var current_state: State
@export var animations: AnimationPlayer
@export var physics: PhysicsComponent
#Initialize the state machine by giving each child state a reference to the
#parent object it belongs to and enter the default starting_state.
func init(parent: CharacterBody2D) -> void:
for child in get_children():
child.parent = parent
child.animations = animations
child.physics = physics
#Initialize to the default state
change_state(initial_state)
#Change to the new state by first calling any exit logic on the current state
func change_state(new_state: State) -> void:
if current_state:
current_state.exit()
current_state = new_state
current_state.enter()
print(current_state)
#Pass through functions for the player to call,
#handling state changes as needed
func process_physics(delta: float) -> void:
var new_state: State = current_state.process_physics(delta)
if new_state:
change_state(new_state)
func process_input(event: InputEvent) -> void:
var new_state: State = current_state.process_input(event)
if new_state:
change_state(new_state)
func process_frame(delta: float) -> void:
var new_state: State = current_state.process_frame(delta)
if new_state:
change_state(new_state)
The state machine manager if needed
Idle_state.gd
extends State
@export
var fall_state: State
@export
var jump_state: State
@export
var move_state: State
func enter() -> void:
super()
func process_input(event: InputEvent) -> State:
if physics.check_jump(parent, event):
return jump_state
if physics.check_movement(event):
return move_state
return null
func process_physics(delta: float) -> State:
#physics.move(parent)
if !parent.is_on_floor():
return fall_state
return null
Move_state.gd
extends State
@export
var fall_state: State
@export
var idle_state: State
@export
var jump_state: State
func enter() -> void:
super()
func process_input(event: InputEvent) -> State:
if physics.check_jump(parent, event):
return jump_state
return null
func process_physics(delta: float) -> State:
physics.manage_movement(parent, delta)
if !parent.velocity:
return idle_state
#parent.animations.flip_h = movement < 0
physics.move(parent)
if !parent.is_on_floor():
return fall_state
return null
Jump_state.gd
extends State
@export
var fall_state: State
@export
var idle_state: State
@export
var move_state: State
func enter() -> void:
super()
physics.jump(parent)
func process_physics(delta: float) -> State:
if parent.velocity.y < 0:
return fall_state
#if movement != 0:
#parent.animations.flip_h = movement < 0
physics.manage_movement(parent, delta)
if parent.is_on_floor():
if !physics.get_direction():
return move_state
return idle_state
return null
Fall_state.gd
extends State
@export
var idle_state: State
@export
var move_state: State
func enter() -> void:
super()
func process_physics(delta: float) -> State:
#if movement != 0:
#parent.animations.flip_h = movement < 0
physics.manage_movement(parent, delta)
if parent.is_on_floor():
if !physics.get_direction():
return move_state
return idle_state
return null
And this are all the state so far.
I will leave a link to video for showing exactly what happens here.
I don’t really know what is wrong. I suspected that is from the state machine, changing from the idle to move and having a hiccup but i don’t have discovered anything related with that.
Most probably will be a stupid reason but i can not find a solution and chatgpt wasn’t very helpfull either.