I need to create a Stamina System but i can't find a useful tutorial

So i want to create a Stamina System in wich after 1-2 seconds of running the stamina bar gets to 0 and then it regenerates in like 5 seconds (And btw if someone could help me to make my running script not be toggleable i would apreciate it, i want to press shift and run while shift is pressed, rn when i press shift it starts running until you press shift again, thanks in advance <3), here’s my code:

using UnityEngine;

public class MovimientoJugador : MonoBehaviour
{
    public float speed;
    public Rigidbody2D rb;
    private Vector2 moveVelocity;
    public float runningspeed;

    // Update is called once per frame
    void Update()
    {
        Vector2 moveimput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));

        moveVelocity = moveimput.normalized * speed;
    }

    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + moveVelocity * Time.fixedDeltaTime);

        if (Input.GetKey(KeyCode.LeftShift))
        {
            rb.MovePosition(rb.position + moveVelocity * runningspeed * Time.fixedDeltaTime); ;
        }
    }

   

}
public class Testingblabla : MonoBehaviour
{
    public float MaxStamina = 1;
    public float ActualStamina = 1;
    public float LoseStaminaPerSecondAmount = 0.5f;
    public float TimeToRegenerateFullStamina = 5f;

    public float speed;
    public Rigidbody2D rb;
    private Vector2 moveVelocity;
    public float runningspeed;


    public bool isRunning;



    void Update()
    {
        Vector2 moveimput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));

        moveVelocity = moveimput.normalized * speed;

        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            isRunning = !isRunning;
        }
    }

    private void FixedUpdate()
    {

        if (isRunning)
        {
            rb.MovePosition(rb.position + moveVelocity * runningspeed * Time.fixedDeltaTime);

            ActualStamina -= LoseStaminaPerSecondAmount * Time.fixedDeltaTime;
            if(ActualStamina <= 0)
            {
                ActualStamina = 0;
                isRunning = false;

            }
        }
        else
        {
            rb.MovePosition(rb.position + moveVelocity * Time.fixedDeltaTime);

            ActualStamina += (MaxStamina / TimeToRegenerateFullStamina) * Time.fixedDeltaTime;
            if(ActualStamina > MaxStamina)
            {
                ActualStamina = MaxStamina;
            }
        }
    }
}

That should fit . If there is anything you don’t understand (or doesn’t work), tell me.

1 Like

(Need to double Post as the OP saw my answer [liked it] and i need to add some infos)

With this solution, hardcore players and speedrunners will be able to run forever if they press leftShift every frame; to make it impossible, you should add a check in the update loop, like this one:

    void Update()
    {
        Vector2 moveimput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
        moveVelocity = moveimput.normalized * speed;
        if (Input.GetKeyDown(KeyCode.LeftShift) && ActualStamina - LoseStaminaPerSecondAmount * Time.fixedDeltaTime > 0)
        {
            isRunning = !isRunning;
        }
    }
1 Like

I was about to write you a dm about some stuff that i didn’t understood, guess there are a couple more things i need now xd, thanks a lot for helping tho, im going to post the questions here so anyone else can see them

So i kinda get it but there are some things that i havent learned yet, could you write some annotations on it? You know with the // thingy, thanks!

For example:

//here what i dont get is why when you press shift "IsRunning" turns into "!isRunning", doesn't that mean that it is not running?

if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            isRunning = !isRunning;
        }

i also don’t know what “-=” means, nor “<=” i mean it’s a very happy face, that’s all i know (?, also idk what “+=” means, i assume it’s related to “-=”, bassicaly i barely understand the fixedupdate thing (The most important part xd), apreciate it if you helped with this thingies, thanks!

and i know that the “&&” thing means “also if this is happening” but idk what comes after means ;(((

        if (Input.GetKeyDown(KeyCode.LeftShift) && ActualStamina - LoseStaminaPerSecondAmount * Time.fixedDeltaTime > 0)
        {
            isRunning = !isRunning;
        }
    }

IF ((You press LeftShift) and also (The actual stamina minus the amount of stamina you loose every fixedframe is superior to 0)) “>” Means “is superior to”.

Let’s say every fixedFrame, you loose 0.1 stamina. If the actual stamina you have minus 0.1 is under 0, that means you didn’t have enough stamina to run.

Then : isRunning = !isRunning :

A boolean with a “!” before it, means the opposite of it.
If you are running, it is equal to true. If your not running, it’s equal to false.
If you press shift, you turn it into its opposite.
If you are running and press shift, you stop running.
If you aren’t running and press shift, you start running.

ActualStamina -= LoseStaminaPerSecondAmount * Time.fixedDeltaTime;
            if (ActualStamina <= 0)
            {
                ActualStamina = 0;
                isRunning = false;
            }

int number = 10;
number -=3;

number is now equal to 7.

it’s like writing : ActualStamina = (ActualStamina ) - LoseStaminaPerSecondAmount * Time.fixedDeltaTime;

Now,

Time.fixedDeltaTime is equal to 1 divided by the number of fixedFrames that happen every second.

number = 0;

void FixedUpdate()
{
number += 1 * Time.fixedDeltaTime;
}

Every fixedFrame, you add one divided by the number of fixedFrames that happen every second to your number.
After one second, the number will be equal to 1. equal to 2 after two seconds.

if (ActualStamina <= 0)
            {
                ActualStamina = 0;
                isRunning = false;
            }

" <= " means “is inferior or equal to”.

So if your actual stamina is zero, you stop running. Also, you put back your actual Stamina to zero, just in case your stamina was under zero. This means it’s impossible to have less than 0 stamina.

1 Like

Hey man i really aprecciate you trying to help me to do this but i’m really not understanding this, is there a simpler way to do it? I have been using unity for like 2 weeks ;(((

This is the simplest way to do it unfortunately. Good new is, i’m available to help you understand. (I might not be the best teacher, but i’ll do my best).

Ask questions about what you don’t understand, for each step, one by one. Try to tell me what you think it does, i’ll tell you if you are right, or tell you what it actually does in a way you will have more chances to understand.

1 Like

Alright cool, so first of all this:

if (Input.GetKeyDown(KeyCode.LeftShift) && ActualStamina - LoseStaminaPerSecondAmount * Time.fixedDeltaTime > 0)
        {
            isRunning = !isRunning;
        }

I understand that if the imput gets that i pressed shift and that the stamina is grater than 0 then “isRunning” is true, but the “ActualStamina - LoseStaminaPerSecondAmount” i don’t understand

So this is a security to ensure players can’t try to run if they don’t have enough stamina to run. It could happen if someone was running, spent all of his stamina (so it made him stop running) and tries to run again instantly.

Fixed Uptade is called 50 times per second. You must loose 0.5 stamina every second. This means you loose 0.5 divided by 50 of your stamina every time fixed Update happens : You loose 0.01 stamina every fixed update.

“LoseStaminaPerSecondAmount * Time.fixedUpdate = 0.01”

Let’s say you actually have 0.8 Stamina, 0.8 - 0.01 is equal to 0.79 ; You have enough stamina to run.

Now let’s say you actually have 0.005 Stamina, 0.005 - 0.01 is equal to -0.005, it’s under zero, that means you don’t have enough stamina to run.

if (your actual stamina) minus [[ (The amount of stamina you loose every second) divided by 50 ]] is under zero, it means you don’t have enough stamina to start running.

        if (Input.GetKeyDown(KeyCode.LeftShift))//If you press the button
        {
            if(     (ActualStamina - LoseStaminaPerSecondAmount * Time.fixedDeltaTime) > 0)//If you have enough stamina
            {
                isRunning = !isRunning;
            }
        }

This code does the exact same thing, but maybe it’s easier for you to read.

1 Like

Oooo i think i get it, “Actual stamina” is for example 0.8 and then you substract 0.01 wich is “LoseStaminaPerSecondAmount” that would give you 0.79 and if the result (0.79) is greater than 0 (>0) then “isRunning” is going to turn true, i get it!!! Thanks a million men, there’re still some stuff i dont understand tho, and i’ll tell ya in another reply, if you are ok with that.

That’s basically it, well done ^^.
Of course i’m okay with that, if i decided to help you, i won’t just let you down all of a sudden.

1 Like

Awesome man, so this line:

private void FixedUpdate()
    {
        if (isRunning)
        {
            rb.MovePosition(rb.position + moveVelocity * runningspeed * Time.fixedDeltaTime);
            ActualStamina -= LoseStaminaPerSecondAmount * Time.fixedDeltaTime;
            if(ActualStamina <= 0)
            {
                ActualStamina = 0;
                isRunning = false;
            }
        }

I get that if “isRunning” is true then the character is going to run, then the part below is what i do not understand, “ActualStamina -= LoseStaminaPerSecondAmount* Time.fixedDeltaTime;” i understand that what is supposed to do is that every frame, fixedframe rather it is going to extract 0.01 points “LoseStaminaPerSecondAmount” from actual stamina, but i dont exactly understand what “-=” means, does that mean that it is going to extract “LoseStaminaPerSecondAmount” from “ActualStamina” every fixed frame? if so, does that mean that “+=” would add 0.01? And then the other part “if (ActualStamina <=0)” i do understand, if ActualStamina goes below 0 it is going to be set to 0 (ActualStamina = 0;) and is going to make “isRunning” false (isRunning = false;) right?

HAHAHA “; )” TURNS INTO A WINKY FACE

Sorry for the late answer.

Yes it’s mostly true.
Actually, “if (ActualStamina <=0)” isn’t the same as "if (ActualStamina < 0).

<0 means below zero.
<=0 means equal to or below 0.

It means that if it is below zero, it will make isRunning false, but will also work if your actual stamina is totally equal to zero.

The rest is entirely correct.

1 Like

Oh shit nice, well now for the last and final part of the journey:

  else
        {
            rb.MovePosition(rb.position + moveVelocity * Time.fixedDeltaTime);
            ActualStamina += (MaxStamina / TimeToRegenerateFullStamina) * Time.fixedDeltaTime;
            if(ActualStamina > MaxStamina)
            {
                ActualStamina = MaxStamina;
            }

so i get that if “isRunning” is false then the stamina is going to regenerate, what i dont get is why you have to divide “MaxStamina” for “TimeToRegenerateFullStamina”, whats below means that if the actualstamina surpasses the maxstamina it would be set to maxstamina ;))). Oh wait i think i got the first part, every fixedframe it is going to add 1(MaxStamina)/5(TimeToRegenerateFullStamina) right?

well, every second not every fixedframe, that would be way to quick

Exactly. It will add every 50th of a second (1/5)/50, meaning it will smoothly resplenish a fifth of the stamina per second.

1 Like

Awesome, thanks for giving me the code and helping me figure it out, i still have to add a lot of stuff to the game, but i ain’t goint to bother you with it, imma search some other tutorials for it, and if i don’t find any, well i’m coming back to the forums baby, but seriously thanks for your help <33