Player Stamina is being removed instantly when sprinting & not stopping sprint when out of Stamina

Currently been messing about with Unity and following different tutorials and combining them.

I have a movement script and resource script for stamina, when you use up stamina it decreases and after a short time it begins regenerating. I have sprinting set to decrease stamina by 10 each time however, when it is reduced to 0 which it seems to do instantly I can continue sprinting. How do I reduce the stamina resource incrementally instead of instantly and stop sprinting when the player doesn’t have enough stamina to sprint?

Stamina Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerResources : MonoBehaviour
{

    public Slider staminaBar;

    public int maxStamina = 100;

    public int currentStamina;

    private WaitForSeconds regenTick = new WaitForSeconds(0.1f);
    private Coroutine regen;

    public static PlayerResources instance;


    private void Awake()
    {
        instance = this;
    }

    private void Start()
    {
        currentStamina = maxStamina;

        staminaBar.maxValue = maxStamina;

        staminaBar.value = maxStamina;
    }

    public void UseStamina(int amount)
    {
        if (currentStamina - amount >= 0)
        {
            currentStamina -= amount;
            staminaBar.value = currentStamina;

            if (regen != null)
                StopCoroutine(regen);

            regen = StartCoroutine(RegenStamina());
        }
        else
        {
            Debug.Log("Not enough Stamina");
        }
    }

    private IEnumerator RegenStamina()
    {
        yield return new WaitForSeconds(2);

        while (currentStamina < maxStamina)
        {
            currentStamina += maxStamina / 100;
            staminaBar.value = currentStamina;
            yield return regenTick;
        }
        regen = null;
    }
}

Player Movement Script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewPlayerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float speed;
    public float walkSpeed = 8f;
    public float sprintSpeed = 20f;
    public float jumpHeight = 3f;
    public float gravity = -9.81f;

    bool isGrounded;
    bool isSprinting

    public Transform groundCheck;
    public float groundDistance = 0.1f;
    public LayerMask groundMask;

    Vector3 velocity;


    void Update()
    {
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }

        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        Vector3 move = transform.right * x + transform.forward * z;

        controller.Move(move * speed * Time.deltaTime);

        if (Input.GetKey(KeyCode.LeftShift) && isSprinting)
        {
            speed = sprintSpeed;
            PlayerResources.instance.UseStamina(10);
        }
        else
        {
            isSprinting = false;
            speed = walkSpeed;
        }


        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
            controller.slopeLimit = 100.0f;
            PlayerResources.instance.UseStamina(1);
        }

        velocity.y += gravity * Time.deltaTime;

        controller.Move(velocity * Time.deltaTime);

    }
}

I guess I’d have to create a new bool for isSprinting and then check for stamina usage/set speed?

First of all, I don’t see anywhere that the cost to sprint is being multiplied by Time.deltaTime, which means you’ll consume stamina at a variable speed depending on your framerate. In a simple game running on a powerful machine that is subtracting 1 stamina per frame, you could plausibly burn through 100 stamina in under a second even with no other bugs. That wouldn’t explain your stamina going to zero literally instantly, but if by “instantly” you meant “quickly” then that might be your problem.

(You probably want stamina to be a float, not an int, so that you can remove fractional amounts of stamina when a fractional second passes.)

Second, if you try to use more stamina than you have, you are printing a Debug.Log message, but nothing in your player movement script is going to notice. If you want running out of stamina to stop the player from sprinting, then you need an “if” statement somewhere that checks whether the stamina cost was actually paid. (You may want to modify the UseStamina() function so that it returns a bool indicating whether it was successful.)

Also I don’t know what you think line 48 of player movement is doing.

So, all of the int in the Stamina script should be float, does that include the beginning of the

public void UseStamina(int amount) //FROM
public void UseStamina(float amount) //TO

changing those I’d have the
PlayerResources.instance.UseStamina(10f * Time.deltaTime); like that then?

I apologize for asking such simple/stupid questions but I’m just trying to wrap my head around how all of this works. I’m enjoying watching youtube videos that show writing this code but, at the end of the day I’m not learning anything but copying what someone else types.

Yes, but don’t forget to also change the variable declaration from “public int currentStamina” to “public float currentStamina”. (You may want to also change maxStamina while you’re at it, though that’s not essential.)

As @Antistone says, you need to incorporate Time.deltaTime to your code. I don’t know if you already undesrtand why and what deltaTime is, but I’ll try to explain it just in case :smile:

Games run in some frame rate, lets say 60FPS (frames per second). It means that every second game is being rendered 60 times (among other things). This frame rate may be modified by options (like forcing it to be max 30fps) or by hardware if unlimited, so the frame rate of the same game may be 10fps if runned on a mobile and 300fps if runned on a computer. Due to this, you have delta time to make your code independant of frame rate.

What’s delta time(Time.deltaTime in Unity)? So, it’s basically the time in second from the last frame to the current frame. Let’s say you want your character to run 3 meters every second. If you add this 3 meter in your Update function, it will result in a speed of 3 meters EVERY FRAME. This means that if your game runs at 10fps, it will be 10 * 3 = 30 meters per second, and if it runs at 60fps it will be 60 * 3 = 180 meters per second. This lead to this problem: your code is depending on your framerate, so if the frame rate changes (for example due to a intense-vfx moment that low your fps from 60 to 50) it will result in a slower game during this time.
So, how to fix this? Easy, using delta time! Lets says your game runs at constant and smooth 60 fps, so each frame takes 1/60 = 0.1667 seconds, so your delta time is 0.1666 seconds. Now, to use it to calculate the speed you need to apply on EACH frame if you want a 3m/s speed: speed = 3 * Time.deltaTime = 3 * 0.1666 = 0.05; Now, you are getting a real speed of 3m/s in your Update function, and it will still being 3m/s even if the frame rate changes :smile:

Hope to be helpulf!