(SOLVED) Having a bug while trying to instantly turn around using a move_toward function

Godot Version

Godot 4.6

Question

(Solved! Updated code in replies)

I originally asked this question on r/godot, but unfortunately, the replies weren’t too helpful.

Basically, what I’m trying to do is code a movement system similar to Pizza Tower as my first project. In that game, you have different “mach states” based on your speed and the amount of time you’ve been running. I’ve already made a few different states for player movement, including idling, walking, jumping, and falling.

I’m currently making an early acceleration stage (aptly named “smoldashin”), for when the player first starts dashing. I want the player to be able to instantly turn around in this state. Right now, if the player turns around, the “move_toward” function will slow him down, and then speed up to the new target speed (which is multiplied by the facing direction), effectively creating a skidding state. I do want to have the player skid while dashing, but in a later state when he’s amassed more speed.

The bug I’m running into is that I can’t just multiply the player’s movement speed by the direction that’s being held, as doing so causes a weird bug that makes the player stutter in place while holding left. It acts exactly the same as before when holding right, though. This should be basic, but it’s evaded me for about two hours now.

I can’t find anything on this online except for shoddy AI overviews, so I was hoping somebody with experience in 2D platformers could help me out here

TLDR; I need instant turning while the player is moving using the “move_toward” function.

Here’s the code:

extends State

class_name SMOLDASHIN

@onready var state_label: Label = $"../../../CanvasLayer/MarginContainer/StateLabel"
@export var animated_sprite: AnimatedSprite2D
var state = "SMOLDASHIN"
var init_speed = 180.0
var SPEED = 120.0
const max_speed = 200.0
const GRAV = 900
const ACCEL = 150.0

func enter():
	# for debugging
	state_label.text = "state: " + str(state)
	
	
func physics_update(delta: float):
	# Applies gravity
	var bob = state_machine.get_parent()
	if not bob.is_on_floor():
		bob.velocity.y += GRAV * delta

	var direction := Input.get_axis("moveleft", "moveright")
	var target_speed = bob.facing_dir * max_speed
		# Flips sprite and facing direction depending on which direction is held
	if direction > 0:
		animated_sprite.flip_h = false
		bob.facing_dir = 1
	elif direction < 0:
		animated_sprite.flip_h = true
		bob.facing_dir = -1
	
	# Dashes in the facing direction regardless of input
	if direction == 0:
		bob.velocity.x = move_toward(bob.velocity.x, target_speed, ACCEL * delta)
	# Handles movement while speeding up
	elif direction != 0:
		bob.velocity.x = move_toward(bob.velocity.x, target_speed, ACCEL * delta)

	
	
		
	bob.move_and_slide()
	
func handle_input(event: InputEvent):
	pass

Hopefully someone expert will jump in here–I’m not one. But what happens if you move the target_speed assignment to below that if/elif?

Oh, my bad, I figured it out and forgot to delete this post lol. I did end up moving the target_speed assignment below there, and ended up using sign() to change directions.

Here’s the updated code as of now if anybody reading this is curious:

extends State

class_name player_first_gear

@onready var state_label: Label = $"../../../CanvasLayer/MarginContainer/StateLabel"
@export var animated_sprite: AnimatedSprite2D
var state = "first gear"
var init_speed = 70
const max_speed = 160
const GRAV = 900
const ACCEL = 240

func enter():
	# for debugging
	state_label.text = "state: " + str(state)
	var bob = state_machine.get_parent()
	if bob.velocity.x == 0:
		bob.velocity.x = bob.facing_dir * init_speed
	
func physics_update(delta: float):
	# Applies gravity
	var bob = state_machine.get_parent()
	if not bob.is_on_floor():
		bob.velocity.y += GRAV * delta

	var direction := Input.get_axis("moveleft", "moveright")
		# Flips sprite and facing direction depending on which direction is held
	if direction > 0:
		animated_sprite.flip_h = false
	elif direction < 0:
		animated_sprite.flip_h = true
		
	# Handles movement while speeding up
	if direction != 0:
		bob.facing_dir = sign(direction)
		
		if sign(bob.velocity.x) != bob.facing_dir:
			bob.velocity.x = bob.facing_dir * abs(bob.velocity.x)

	var target_speed = bob.facing_dir * max_speed		
	# Dashes in the facing direction regardless of input
	bob.velocity.x = move_toward(bob.velocity.x, target_speed, ACCEL * delta)
	
	# Kicks into Second Gear when reaching the target speed
	if bob.velocity.x == target_speed:
		state_machine.change_state("player_second_gear")
	
	bob.move_and_slide()
	
func handle_input(event: InputEvent):
	var bob = state_machine.get_parent()
	var direction := Input.get_axis("moveleft", "moveright")
	if bob.is_on_floor():
		if Input.is_action_just_released("run"):
			if direction != 0:
				state_machine.change_state("player_walkin")
			else:
				state_machine.change_state("player_idle")
		if Input.is_action_just_pressed("jump"):
			state_machine.change_state("player_first_gear_jumpin")