help with stamina mechanic!!

Godot Version

4.6.3 stable

Question

hi!! i’m currently trying to implement a sprinting mechanic with stamina for a game i’m making and every part of it works fine except for one thing: when you keep holding the sprint key until it hits 0, the stamia doesn’t recharge (this also includes if you were to let go of sprint then hold it again)

the intended behaviour is to normally let the player sprint by increasing their speed and camera tilt angle when holding the sprint key (in this case, left-shift). however, once the meter reaches 0, what should happen is that it slows down the player (as if they are fatigued) and not let the player sprint until the bar is full again

literally every other part of this works other than this. is there any way to make the game ignore the input during recharge or is there just a flaw in this code i’m being blind to? any help is appreciated!!!

func _physics_process(delta):
	#[...]
	if Input.is_action_pressed("sprint") && stamina != 0:
		if canSprint:
			angle=6
			SPEED=7.5
			stamina -= 20 * delta
	else:
		if stamina < 100 && canSprint:
			angle=2.5
			SPEED=5
		if stamina <= 0:
			canSprint = false
			angle=1
			SPEED=2.5
		if stamina == 100:
			canSprint = true
		stamina += 20 * delta
	stamina = clamp(stamina, 0, 100)
	bar.set_value(stamina, true)
	#[...]

i think your problem is logic one - because you only remove sprint when you’re not sprinting, try removing else and just leave it as it is, then it should work

Research floating point error. Your stamina will never be exactly 0, so your check stamina != 0 won’t work as you expect it to. Change it to stamina > 0 and it should work, assuming the rest of your code works fine.

he have clamp so it shouldn’t be a problem

This can still be a problem, because computers interpret numbers differently than humans and what seems equal to humans might not seem equal to computers. So that’s still the first thing I would change and see if it works.

Try this:

if Input.is_action_pressed("sprint") && not is_zero_approx(stamina):

@NOTIdealDev can you elaborate on your solution? i’m not quite sure what you mean TwT

also: replacing != with > made the code work the exact same way, and replacing the second clause with not is_zero_approx broke the canSprint check (i.e. it never activates the slower speed and you can immediately sprint again after the bar starts recharging)

your code have 2 segments:

  1. If you press shift and have stamina

  2. If you don’t have stamina and you don’t press the shift

So all of your lines like “if stamina is < 100” or “if stamina == 100” will only work when you’re not pressing shift, and stamina is equal zero, that’s how boolean logic works

if you wanted to check these, i’d suggest you doing it outside if block like that:

func _physics_process(delta):
	#[...]
	if Input.is_action_pressed("sprint") && stamina != 0:
		if canSprint:
			angle=6
			SPEED=7.5
			stamina -= 20 * delta
    if stamina < 100 && canSprint:
		angle=2.5
		SPEED=5
	if stamina <= 0:
		canSprint = false
		angle=1
		SPEED=2.5
	if stamina == 100:
		canSprint = true
	stamina += 20 * delta
	stamina = clamp(stamina, 0, 100)
	bar.set_value(stamina, true)
	#[...]

Now you’ll always check for stamina levels, regardless if it’s zero and shift isn’t pressed

@NOTIdealDev unfortunately after testing that solution a couple times over (mostly as sanity checks) using the code you attached just entirely stops the player sprinting

any ideas?

My guess is you’re doing something in the code that you didn’t show us that’s causing the problem.

it’s because you need to adjust it, idk how your entire game works, but if you did stamina < 100 and stamina == 100 at the same time, it wouldn’t work

you need to add additional checks, like “if restored stamina” or smth like that

from what i understand you want player to sprint, and if he lost all of his stamina - he need to replenish it back to 100 to sprint again, then adding restoration flag would help, but it requires testing from you

just remember to don’t have these checks inside else statement

@dragonforge-dev i’ll provide the full movement code for reference

func _physics_process(delta):
	
	if not is_on_floor():
		velocity.y -= gravity * delta

	var input_dir = Vector3.ZERO
	var movetoward = Vector3.ZERO
	input_dir.x = Input.get_vector("move_left", "move_right", "move_forward", "move_backward").x
	input_dir.y = Input.get_vector("move_left", "move_right", "move_forward", "move_backward").y
	input_dir=input_dir.normalized()
	var angle = 2.5
	if Input.is_action_pressed("sprint") && stamina != 0:
		if canSprint:
			angle=6
			SPEED=7.5
			BOB_FREQ = 1.8
			stamina -= 20 * delta
	elif Input.is_action_pressed("sprint") && !canSprint:
		stamina += 20 * delta
	else:
		if stamina < 100 && canSprint:
			angle=2.5
			SPEED=5
			BOB_FREQ = 1.2
		if stamina <= 0:
			canSprint = false
			angle=1
			SPEED=2.5
			BOB_FREQ = 0.6
		if stamina == 100:
			canSprint = true
			angle=2.5
			SPEED=5
			BOB_FREQ = 1.2
		stamina += 20 * delta
	stamina = clamp(stamina, 0, 100)
	bar.set_value(stamina, true)
	var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	direction *= SPEED
	velocity.x = move_toward(velocity.x,direction.x, HORIZONTAL_ACCELERATION * delta)
	velocity.z = move_toward(velocity.z,direction.z, HORIZONTAL_ACCELERATION * delta)

	var t = delta * 6
	if Input.mouse_mode==Input.MOUSE_MODE_CAPTURED: 
		rotation_degrees=rotation_degrees.lerp(Vector3(input_dir.normalized().y*angle,rotation_degrees.y,-input_dir.normalized().x*angle),t)
	
	move_and_slide()
	force_update_transform()
	
	if velocity.length() > 0:
		if is_on_floor():
			t_bob += delta * velocity.length() * headbob_multiplier
			camera.transform.origin = _headbob(t_bob)

i’ll try this real quick

I meant the whole file. where is stamina defined? Does it have a setter? Does anything else in the file modify it?

TBH, you’re already doing some really weird things in this file. Like turning one line of getting input into three lines.

will admit most of the movement was from a 3d first person controller template :sob:

and i mean if it works it works i’m not really going for optimisation at the minute i just wanna get this bloody thing working

this worked!!! no idea why i never thought to do that but it did do the trick

thank you so much!!!