I’m trying to make a sprint and stamina mechanic but my code keeps crashing when i press SHIFT at the beggining but when I press A or D and then SHIFT it’s working. Could someone tell me what’s wrong?
extends CharacterBody2D
var SPEED = 300.0
const JUMP_VELOCITY = -400.0
var double_jump_control = 1
var stamina = 100.0
var is_sprinting: bool
@export var StaminaBar: ProgressBar
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_just_pressed("SPACE") and double_jump_control > 0:
velocity.y = JUMP_VELOCITY
double_jump_control -= 1
if is_on_floor():
double_jump_control = 1
var direction := Input.get_axis("A", "D")
if direction:
velocity.x = SPEED * direction
else:
velocity.x = move_toward(velocity.x, 0, (SPEED)/10)
if Input.is_action_just_pressed("SHIFT") and stamina > 0:
SPEED = 500
while stamina > 0 and Input.is_action_pressed("SHIFT"):
if velocity.x != 0:
await get_tree().create_timer(0.07).timeout
stamina -= 1
if Input.is_action_just_released("SHIFT"):
SPEED = 300
await get_tree().create_timer(2).timeout
while stamina < 100 and Input.is_action_pressed("SHIFT") == false:
stamina += 1
await get_tree().create_timer(0.03).timeout
if stamina == 0:
SPEED = 300
StaminaBar.value = stamina
$"Current Speed".text = "Current speed: " + str(velocity.x)
move_and_slide()
In your while loop when you press shift, nothing happens if velocity.x is 0. That will enter an infinite loop and lock the program up. Take the await timer out of that if clause and it might fix your issue as the input system will have a chance to update.
i.e.
if Input.is_action_just_pressed("SHIFT") and stamina > 0:
SPEED = 500
while stamina > 0 and Input.is_action_pressed("SHIFT"):
if velocity.x != 0:
stamina -= 1
await get_tree().create_timer(0.07).timeout
Also, consider doing reactions to inputs in _process rather than _process_physics, which gets called multiple times per frame.
To add to the previous answer, I don’t think a loop is what you want to have here. Currently you are blocking the game-loop. I think what you might want for a ‘sprint’ mechanic is to just check every frame if the button is pressed and then lower the stamina (and move the character). Or alternatively handle the input in _input and change the speed accordingly.
This is not true per-se. _physics_process is called at a fixed rate (e.g. 60 times per second) while _process is frame-rate dependent. So it might be called more or less often or even at the same rate.
If you want to move your CharacterBody2D an handle physics calculations/collisions (e.g. move_and_slide) you should do so in _physics_process (see Idle and Physics Processing — Godot Engine (stable) documentation in English).
Oh yes, of course any physics/movement code should go in _physics_process. State/AI stuff should go in _process imo. Input handling in _process, but the _input() callback sounds like the ideal way to handle input - I haven’t got round to that yet but am definitely gonna do it that way going forward