Need help with simple sprint & stamina code

I was coming up with a stamina system and making some notes. Now that I’ve started coding it, it turns out to be surprisingly difficult. Mainly the logic. I can’t seem to get the basics down.

What I’m currently trying to accomplish is this:

• Player has 100 stamina. (done)

• Player sprints by holding Left Shift. It speeds them up and drains stamina over time. (done)

• Player stops sprinting, they slow down (done)

• If there’s stamina left, it refills over time (done)

• Stamina hits 0, timer starts counting down from 3 seconds (done)

• Player should also be forced to stop sprinting (having problems)

• Timer hits zero, stamina starts refilling and timer is reset (having problems)

• Player needs to hold down shift again to sprint (having problems)

I’ve gone through about 4 different designs, and one issue that is always occurring is if I’m holding shift as the timer hits 0, it resets and starts counting down again, but nothing happens to the stamina or player speed.

Here’s the first design:

``````if (Input.GetKey(KeyCode.LeftShift) && staminaSlider.value > 0) {

currentSpeed = runSpeed;
staminaSlider.value -= 1;
}

else if (staminaSlider.value == 0) {

currentSpeed = walkSpeed;

staminaTimer -= Time.deltaTime;
if (staminaTimer <= 0) {

staminaTimer = rechargeTime;
staminaSlider.value += 1;
}
}

else if (staminaSlider.value > 0) {

currentSpeed = walkSpeed;
staminaSlider.value += 1;
}
``````

Here’s the most recent:

``````if (staminaSlider.value == 0) {

running = false;

staminaTimer -= Time.deltaTime;

if (staminaTimer <= 0) staminaTimer = rechargeTime;
}

if (staminaTimer == rechargeTime) {

if (Input.GetKeyDown(KeyCode.LeftShift)) running = true;
else if (Input.GetKeyUp(KeyCode.LeftShift)) running = false;
}

if (running) {

currentSpeed = runSpeed;
staminaSlider.value -= 1;
}

else {

currentSpeed = walkSpeed;
staminaSlider.value += 1;
}
``````

I’ve decided on using keyDown and keyUp which changes a bool, to give myself more flexibility in how the code behaves. But even so, the issue stated above still occurs when I hold down shift.

P.S. I’ll gladly elaborate on things if need be.

I had a quick Look, try removing the “else” from;

``````else if (Input.GetKeyUp(KeyCode.LeftShift)) running = false;
``````

also, what is happening here; is this Happening every frame?

``````staminaSlider.value -= 1;
``````

Yes, the whole code is in Update(), so the value is being decreased every frame.

Removing the else in that check doesn’t seem to have affected anything.

Also just to restate my intentions more concisely, for clarity.

I want stamina to instantly start refilling when you let go of shift. But if stamina runs out, there should be a 3 second delay before it starts refilling.

Also make sure “drainRate” and “reChargeRate”, are higher than the current value which is 0;

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

public class helpingDudeFromForum : MonoBehaviour
{
public float stamina = 100f;

public float speed;
public float runSpeed = 10f;
public float walkSpeed = 5f;

public float drainRate = 1f;
public float reChargeRate = 1f;

public float fatigueTimer = 0f;
bool isFatigued;

bool isRunning;

void Update()
{
if(Input.GetKey(KeyCode.LeftShift))
{
if(stamina > 0 && !isFatigued)
{
speed = runSpeed;
isRunning = true;
}
else

if(isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;

}
}

if (isRunning)
{
stamina -= Time.deltaTime * drainRate;
}
else

if (!isRunning && stamina > 0)
{
stamina += Time.deltaTime * reChargeRate;
}

if(stamina <= 0f && fatigueTimer <= 3)
{
fatigueTimer += Time.deltaTime;
isFatigued = true;
}
else

if (fatigueTimer >= 3)
{
stamina += Time.deltaTime * reChargeRate;
isFatigued = false;
fatigueTimer = 0;
}

}
}
``````

isRunning is not setting back to false after I let go of left shift, so the stamina keeps being drained and I keep sprinting.
The issue with holding down shift when the timer is done, also remains (timer resets and counts up, and nothing changes with stamina or speed).

When the timer starts counting up, I can press left shift for it to set isRunning to false.

I’ll look over this code in more depth and see where these issues are occurring. Two heads better than one. I’d feel bad if I was just sitting back waiting for people to fix this fully for me.

Also just like to say I really appreciate you improving the initial idea, like adding separate variables for drain and recharge rates, and having it do so based on real time rather than every frame.

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

public class helpingDudeFromForum : MonoBehaviour
{
public float stamina = 100f;

public float speed;
public float runSpeed = 10f;
public float walkSpeed = 5f;

public float drainRate = 1f;
public float reChargeRate = 1f;

public float fatigueTimer = 0f;
bool isFatigued;

bool isRunning;

void Update()
{
if(Input.GetKey(KeyCode.LeftShift))
{
if(stamina > 0 && !isFatigued)
{
speed = runSpeed;
isRunning = true;
}
else

if(isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;

}
}

if(Input.GetKeyUp(KeyCode.LeftShift))
{
if (isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;
}
}

if (isRunning)
{
stamina -= Time.deltaTime * drainRate;
}
else

if (!isRunning && stamina > 0)
{
stamina += Time.deltaTime * reChargeRate;
}

if(stamina <= 0f && fatigueTimer <= 3)
{
fatigueTimer += Time.deltaTime;
isFatigued = true;
}
else

if (fatigueTimer >= 3)
{
stamina += Time.deltaTime * reChargeRate;
isFatigued = false;
fatigueTimer = 0;
}

}
}
``````

btw, I deleted the first script I gave you, I remade it, so try this instead.

and if that last one didnt work, try this, last attempt before i got to bed its 1:30 Am

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

public class helpingDudeFromForum : MonoBehaviour
{
public float stamina = 100f;

public float speed;
public float runSpeed = 10f;
public float walkSpeed = 5f;

public float drainRate = 1f;
public float reChargeRate = 1f;

public float fatigueTimer = 0f;
bool isFatigued;

bool isRunning;

void Update()
{
if(Input.GetKey(KeyCode.LeftShift))
{
if(stamina > 0 && !isFatigued)
{
speed = runSpeed;
isRunning = true;
}
else

if(isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;

}
}
else
{
if (isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;
}
}

if (isRunning)
{
stamina -= Time.deltaTime * drainRate;
}
else

if (!isRunning && stamina > 0)
{
stamina += Time.deltaTime * reChargeRate;
}

if(stamina <= 0f && fatigueTimer <= 3)
{
fatigueTimer += Time.deltaTime;
isFatigued = true;
}
else

if (fatigueTimer >= 3)
{
stamina += Time.deltaTime * reChargeRate;
isFatigued = false;
fatigueTimer = 0;
}

}
}
``````

The second last one works better.

(this one)

I realized what’s most likely happening with the timer issue. As soon as it resets and the stamina starts refilling, since the shift is held down it instantly goes back down to 0 and restarts the timer.

I think there should just be an extra delay, once isFatigued is set to false. So adding a second timer, and having it run once fatigue timer reaches 3, then not allowing shift to do anything until that second timer reaches whatever value.

90% sure that last script should fix it bro

Okay will try it again.

Nope, last script doesn’t fix it unfortunately.

If your still stuck by tomorrow, I will have another look, but I am so tiered now.

it should be very close to that last script, ofc I am doing this all from bed so I cant debug.Log it. gl bro

I decided to get up and try it and fix it for you;

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

public class helpingDudeFromForum : MonoBehaviour
{
public float stamina = 100f;

public float speed;
public float runSpeed = 10f;
public float walkSpeed = 5f;

public float drainRate = 1f;
public float reChargeRate = 1f;

public float fatigueTimer = 0f;
bool isFatigued;

bool isRunning;

void Update()
{
if (Input.GetKey(KeyCode.LeftShift))
{
if (stamina > 0 && !isFatigued)
{
speed = runSpeed;
isRunning = true;
}
else

if (isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;

}
}

if (Input.GetKeyUp(KeyCode.LeftShift))
{
if (isRunning || isFatigued)
{
speed = walkSpeed;
isRunning = false;
}
}

if (isRunning)
{
stamina -= Time.deltaTime * drainRate;
}
else

if (!isRunning && stamina > 0 && stamina <100 )
{
stamina += Time.deltaTime * reChargeRate;
}

if (stamina <= 0f && fatigueTimer <= 3)
{
fatigueTimer += Time.deltaTime;
isFatigued = true;
}
else

if (fatigueTimer >= 3)
{
stamina += Time.deltaTime * reChargeRate;
isFatigued = false;
fatigueTimer = 0;
}

if(stamina < 0f)
{
stamina = 0f;
}

if (stamina > 100f)
{
stamina = 100f;
}

}
}
``````

Wow, thank you so much for going the extra mile mate.

This script still doesn’t solve that problem though.

btw after re-reading both of the last scripts (excluding the most recent one), I see they both do basically the same thing, they’re just slightly differently worded. Namely an else statement that checks for running or fatigue, as opposed to checking for shift being lifted. So I’ll just stick with the last one.

I really think it’s just a simple logic issue. Once the timer hits 3 and stamina starts refilling, because shift is still held down, it drops right back to 0 and the fatigue code starts up again.

I can try my initial suggestion with adding a second timer, once you come back and it somehow failed, we can keep working on it.

bro, I tried it it works. just copy it word by word and try it in the inspector

here you go, I even made you a video, watch it in HD