Someone please help, I cannot figure out what I'm doing wrong

Godot Version

4.5

Question

So I’m following this tutorial on making a state machine in Godot 4 to define movement and stuff, and I followed the tutorial exactly (at least I’m pretty sure I did) but when I run the project my player cannot move at all and I have no idea what I’m doing wrong.

The way its supposed to work is that I define a variable called direction based on the input strength (I already set up inputs in the Input Map). When I first boot up the project the player is in the “idle state”, and every tick it checks to see if the direction variable is greater than 0, and if so it enters a new state called “walk” which sets my velocity to the direction times a variable called movement speed (which I currently have set to 100 as a default). However, it seems like the character is unable to exit the “idle” state, and I genuinely have no idea what I’ve done wrong.

Here’s the relevant code:

(within the Player script)

class_name Player extends CharacterBody2D

var cardinal_direction : Vector2 = Vector2.DOWN
var direction : Vector2 = Vector2.ZERO

##onready variables
@onready var sprite : Sprite2D = $Sprite2D
@onready var state_machine : PlayerStateMachine = $StateMachine
@onready var animation_player = $AnimationPlayer

# called upon opening scene
func _ready():
	state_machine.Initialize(self)
	pass


# called every frame; delta = time between frames
func _process(_delta):
	
	##movement
	direction.x = Input.get_action_strength("right") - Input.get_action_strength("left")
	direction.y = Input.get_action_strength("down") - Input.get_action_strength("up")
	
	pass

(within the State_Walk script)

class_name State_Walk extends State

@export var move_speed : float = 100.0

@onready var idle : State = $Player/StateMachine/Idle

##What happens when Player enters State
func Enter() -> void: 
	player.UpdateAnimation("walk")
	pass
##What happens when Player exits State
func Exit() -> void:
	pass



##What happens during Process update
func Process(_delta : float) -> State:
	if player.direction == Vector2.ZERO:
		return idle
	
	player.velocity = player.direction * move_speed
	
	if player.SetDirection():
		player.UpdateAnimation("walk")
		pass
	
	return null
##What happens during _physics_process update
func Physics(_delta : float) -> State:
	return null
##What happens with input events in State
func HandleInput(_event : InputEvent) -> State:
	return null

Please format your code properly, it is very difficult to read otherwise.

```gd
# code here
```

From the code you’ve posted here, it doesn’t seem like you are calling move_and_slide() for the player (which is necessary for him to move).

2 Likes

I’m a beginner but i’m pretty sure you can just spell:

var direction_x := Input.get_axis("left", "right")
var direction_y := Input.get_axis("up", "down")

Instead of:

var direction_x := Input.get_action_strength("right") - Input.get_action_strength("left)
var direction_y := Input.get_action_strength("down") - Input.get_action_strength("up")

Input.get_axis() is like the short version of Input.get_action_strength() I think,
Not sure, but I think so.

And I think it’s better to put those direction variables in the _physics_process function instead of the _process function.

I think you should step back from state machines and just try to get the player to move at all. In the player script, call move_and_slide() after setting the player’s velocity based on the direction input and some movement speed. Something like this:

func _physics_process():
    direction = Input.vector("left", "right", "up", "down")    
    velocity = direction * move_speed
    move_and_slide()

See if you’re able to get that to work. Then see if you can figure out how to make the player jump. You seem like a beginner, so I’d say forget about state machines for now. :+1:

1 Like

Good advice :+1:

I was able to get the player to work without relying on State machines, what I’m trying to do now is convert it into a state machine so I don’t end up with spaghetti code later on. Especially cause I have a tendency to drop projects and revisit them months or even years down the line, so I need everything to be neat and readable.

Also I do have move_and_slide called, I just didn’t include my _physics_process in the pasted code for some reason, that’s mb.

func _physics_process(_delta):
	move_and_slide()


func SetDirection() -> bool:
	var new_dir : Vector2 = cardinal_direction
	if direction == Vector2.ZERO:
		return false
	
	
	if direction.y == 0:
		new_dir = Vector2.LEFT if direction.x < 0 else Vector2.RIGHT
	elif direction.x == 0:
		new_dir = Vector2.UP if direction.y < 0 else Vector2.DOWN
	
	if new_dir == cardinal_direction:
		return false
	
	cardinal_direction = new_dir
	sprite.scale.x = -1 if cardinal_direction == Vector2.LEFT else 1
	return true


func UpdateAnimation( state : String ) -> void:
	animation_player.play( state + " " + AnimDirection() )
	pass
	
	
func AnimDirection() -> String:
	if cardinal_direction == Vector2.DOWN:
		return "down"
	elif cardinal_direction == Vector2.UP:
		return "up"
	else:
		return "side"

Who told you that you need to use a state machine to have clean code? The point of having clean code is, you said it yourself, have code that’s easy to read & understand for other people and for yourself in the future. But this state machine that you’re trying to make, it has so many nodes and scripts and it all seems so complicated! The code that I gave you on the other hand is nice and clean, it’s just three lines.

By the way…
sprite.scale.x = -1 if cardinal_direction == Vector2.LEFT else 1
That just flips the sprite horizontally, right? Try this instead:
sprite.flip_h = cardinal_direction == Vector2.LEFT
Now it’s easy to read & understand: the sprite’s h flip depends on the cardinal direction being left.

In the original code, it doesn’t look like you ever call the state.Process() function.
It must be called specifically as it is not the same as a state._process() virtual function. You can also link the tutorial and we can do a comparison.

I’m a little confused because there is no state.Process() function, do you mean current_state.Process(delta) ? The tutorial I used is here: https://www.youtube.com/watch?v=ozUS1cSgFKs&list=PLfcCiyd_V9GH8M9xd_QKlyU8jryGcy3Xa&index=3.

Welp, I figured out what I did wrong…

I’m genuinely about to cry rn because after a week of debugging and messing around trying to fix it, turns out that I just assigned the @onready var wrong > _ <

The state machine node is called PlayerStateMachine, not StateMachine.

As a general remark, this type of simplistic state machine is an inadequate choice for managing player state, especially in action games.