Issue with character movement (for GameJAM and 1st game)

Godot Version

4.3

Question

I have set up a state machine. If it is on the ROLL state, the y velocity of the character (stored just before hitting the floor in y_force global variable) is assigned to the x velocity multiplied by get_axis(). Every ROLL physics frame, the y_force is reduced by 2.
If it goes below 30, the below threshold variable is set to true, and if its set to true, the machine is allowed to change to a different state.
Whenever it enters the ROLL state, it automatically exits to other of the states, on the first frame.
(Regardless of the y_force being much greater.)
The code:

extends Node2D
@onready var player:Character = self.owner
@onready var ray_cast_2d: RayCast2D = $"../Hitbox/RayCast2D"
@onready var timer: Timer = $"../Timer"
@onready var animated_sprite_2d: AnimatedSprite2D = $"../AnimatedSprite2D"

#Basic movement
const velocity_vector := 20
const jump_force := 50

#tweaks
const cenit := -22.25
var has_released_jump := false
var has_jumped := false
#gravity
const base_gravity := 35
var current_Gravity := base_gravity
const fall_gravity := 75
#roll
var y_force:float = 0
var previous_state = default_state
var below_threshold:bool = false

#estados
enum {IDLE,RUNNING,ON_AIR,ROLL}
const default_state = IDLE
var current_state = default_state

func ready():
	ray_cast_2d.enabled = false

func _physics_process(delta: float) -> void:
	match current_state:
		IDLE:
			
			animated_sprite_2d.play(&"0-Idle")
			ray_cast_2d.enabled = false
			has_jumped = false
			has_released_jump = false
			current_Gravity = base_gravity
			
			
			player.velocity.x = 0
			#salto
			if Input.is_action_just_pressed("Jump") and player.is_on_floor():
				player.velocity.y -= jump_force
				
			
			#cambios
			if Input.is_action_pressed("Left") and player.is_on_floor() and not Input.is_action_pressed("Right") or Input.is_action_pressed("Right") and player.is_on_floor() and not Input.is_action_pressed("Left"):
				current_state = RUNNING 
				previous_state = IDLE
			elif not player.is_on_floor():
				current_state = ON_AIR
				previous_state = IDLE
				
		RUNNING:
			
			ray_cast_2d.enabled = false
			has_jumped = false
			has_released_jump = false
			current_Gravity = base_gravity
			
			#movimiento
			if Input.is_action_pressed("Left"):
				player.velocity.x = velocity_vector * -1
				animated_sprite_2d.scale.x = -1
				animated_sprite_2d.play(&"1-Walk")
				
			if Input.is_action_pressed("Right"):
				player.velocity.x = velocity_vector
				animated_sprite_2d.scale.x = 1
				animated_sprite_2d.play(&"1-Walk")
			
			if Input.is_action_pressed("Left") and Input.is_action_pressed("Right"):
				player.velocity.x = 0
				#salto
			if Input.is_action_just_pressed("Jump") and player.is_on_floor():
				player.velocity.y -= jump_force
				
			if previous_state == ON_AIR and Input.is_action_pressed("Down"):
				current_state = ROLL
				previous_state = ON_AIR
				
			
			
			
			#cambios
			if not Input.is_action_pressed("Left") and not Input.is_action_pressed("Right") and player.is_on_floor() or Input.is_action_pressed("Left") and Input.is_action_pressed("Right") and player.is_on_floor():
				current_state = IDLE
				previous_state = RUNNING
			
			elif not player.is_on_floor():
				current_state = ON_AIR
				previous_state = RUNNING
			
		ON_AIR:
			animated_sprite_2d.stop()
			player.velocity.y = player.velocity.y + current_Gravity * delta
			
			
			#movimiento
			if Input.is_action_pressed("Left"):
				animated_sprite_2d.scale.x = -1
				player.velocity.x = velocity_vector * -1
			if Input.is_action_pressed("Right"):
				animated_sprite_2d.scale.x = 1
				player.velocity.x = velocity_vector
			if Input.is_action_pressed("Left") and Input.is_action_pressed("Right"):
				player.velocity.x = 0
				
			if Input.is_action_pressed("Down"):
				player.velocity.y += current_Gravity/10
				
				#release
			if Input.is_action_just_released("Jump") and not has_released_jump:
				player.velocity.y = 0
				player.velocity.y += 10
				has_released_jump = true
				current_Gravity = fall_gravity
				
			if Input.is_action_pressed("Jump"):
				has_jumped = true
				
			if has_jumped and player.velocity.y >= cenit:
				current_Gravity = fall_gravity
				has_released_jump = true
				
			if player.velocity.y >= cenit:
				ray_cast_2d.enabled = true
			else:
				ray_cast_2d.enabled = false
				
			if ray_cast_2d.is_colliding():
				y_force = player.velocity.y
			
			if not below_threshold:
				player.velocity.x = (y_force * Input.get_axis("Left","Right"))
				if y_force > 0:
					y_force -= 2
				if y_force < 30:
					below_threshold = true
				else:
					below_threshold = false
			
			#cambios
			if not Input.is_action_pressed("Left") and not Input.is_action_pressed("Right") and player.is_on_floor() or Input.is_action_pressed("Left") and Input.is_action_pressed("Right") and player.is_on_floor():
				current_state = IDLE
				previous_state = ON_AIR
			elif Input.is_action_pressed("Left") and player.is_on_floor() or Input.is_action_pressed("Right") and player.is_on_floor():
				current_state = RUNNING
				previous_state = ON_AIR
			
				
		ROLL:
			print(y_force)
			player.velocity.y = player.velocity.y + current_Gravity * delta
			animated_sprite_2d.play(&"4-Roll")
			player.velocity.x = (y_force * Input.get_axis("Left","Right"))
			
			if Input.is_action_just_pressed("Jump") and player.is_on_floor():
				player.velocity.y -= jump_force
		
			
			if y_force > 0:
				y_force -= 2
			#velocity_treshold
			if y_force < 30:
				below_threshold = true
			else:
				below_threshold = true
	
			#cambios
			if below_threshold == true:
				if not Input.is_action_pressed("Left") and not Input.is_action_pressed("Right") and player.is_on_floor() or Input.is_action_pressed("Left") and Input.is_action_pressed("Right") and player.is_on_floor():
					current_state = IDLE
					previous_state = ROLL
				elif not player.is_on_floor():
					current_state = ON_AIR
					previous_state = ROLL
				elif Input.is_action_pressed("Left") and player.is_on_floor() or Input.is_action_pressed("Right") and player.is_on_floor():
					current_state = RUNNING
					previous_state = ROLL
			
	player.move_and_slide()

If you decide to, thank you for trying to help me.

Quick note #cambios means #changes

Hello my friend. It can be related to your if statement.

if y_force < 30:
    below_threshold = true
else:
    below_threshold = true

In both cases the below_threshold variable is being set to true, allowing it to enter in the change state condition.

One improvement that u could also do, is to set your var like this:

below_threshold = y_force < 30

Thank you for being comprehensive and taking the time to check, it was such a dumb mistake.
Are you working in any game projects currently? If so you’ve got a fan.

Hahaha it can happen with anyone, don’t worry :sweat_smile:
I am but still in early stage haha thanks!

Don’t forget to mark it as solved. Have a great day!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.