need stamina to only run out when shift is pressed AND the player is moving. Please help.

So currently when I press shift, my players movement speed increases for a period of time (until the value of stamina runs out.) When I am not moving however and am pressing shift, the stamina value runs out anyway.

How can I make it so my stamina only runs out when shift is held down AND my player is using the WASD/Arrow movement keys??

Here is my current movement script:

using UnityEngine;
using UnityEngine.UI;

public class PlayerMovement : MonoBehaviour {

    public Rigidbody rb;
    public float MoveSpeed;
    public float UpSpeed;
    public float shiftSpeed;
    public float stamina = 8f;
    public Image staminaBar;

    bool grounded = true;
    bool running = false;
    bool levelfinished = false;
    bool levelfailed = false;

   


    // Update is called once per frame

    public void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Collectable"))
        {
            other.gameObject.SetActive(false);
        }
    }

    public void OnCollisionStay(Collision collision)
    {
        if (collision.gameObject.CompareTag("Ground")) { grounded = true; }
        if (collision.gameObject.CompareTag("PlatformMoving")) { grounded = true; }

    }

    public void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.CompareTag("Ground")) { grounded = false; }
        if (collision.gameObject.CompareTag("PlatformMoving")) { grounded = false; }
    }


    void FixedUpdate() //for updating physics
    {

        Physics.gravity = new Vector3(0, -150f, 0);



        if (Input.GetKey("w") || Input.GetKey("up"))

        {
            rb.AddForce(0, 0, MoveSpeed * Time.deltaTime, ForceMode.VelocityChange);

        }
      

        if (Input.GetKey("s") || Input.GetKey("down"))
        {
            rb.AddForce(0, 0, -MoveSpeed * Time.deltaTime, ForceMode.VelocityChange);

        }



        if (Input.GetKey("a") || Input.GetKey("left"))
        {
            rb.AddForce(-MoveSpeed / 56, 0, 0 * Time.deltaTime, ForceMode.VelocityChange);

        }



        if (Input.GetKey("d") || Input.GetKey("right"))
        {
            rb.AddForce(MoveSpeed / 56, 0, 0 * Time.deltaTime, ForceMode.VelocityChange);

        }





        if (rb.position.y < -5f)
        {
            FindObjectOfType<EndGame>().gameover();
        }


    }

    public void Update()
    {

        Physics.gravity = new Vector3(0, -150f, 0);

        //not firing consistently in fixedupdate


        if (Input.GetKeyDown("space") && grounded)
        {
            rb.AddForce(0, UpSpeed, 0 * Time.deltaTime, ForceMode.VelocityChange);

        }

        if (Input.GetKeyDown("left shift"))
        {
            MoveSpeed = shiftSpeed;
            running = true;
        }


        if (Input.GetKeyUp("left shift"))
        {
            MoveSpeed = 105f;
            running = false;
        }

        staminaBar.fillAmount = stamina / 8f;

        if (running == false && stamina < 8f) { stamina = stamina + 2 * Time.deltaTime; }

        if (running == true && stamina > 0f) { stamina = stamina - 6 * Time.deltaTime; }

        if (stamina < 1f) { MoveSpeed = 105f; }

        if (stamina != 8f) { shiftSpeed = MoveSpeed; }

        if (stamina >= 1f) { shiftSpeed = 155f; }


     
       
    }
}

I’ve tried a “moving” true and false statements for when keys are pressed etc. but I need a way to check if the player is pressing 1 or more of the movement keys, and when they are not.

Any advice on this is much appreciated :slight_smile:

Best,
J

Since you’re using rigidbodies, you could check velocity vector’s magnitude. If it’s over say, 0.1, then you could consider the player to be moving.

That should solve the problem you’re asking, but I feel the need to be pretentious and critique your use of input, because it could be far simpler. You could make use of Unity’s default input settings - there’s two axes, Horizontal and Vertical, that can be used for WASD/Arrow Key movement. Horizontal is for A/D and left/right, and Vertical does up/down and W/S. The values will always be between -1 and 1, with -1 being left/down and 1 being right/up. Your whole FixedUpdate() function could look something like this (I haven’t tested any of this, by the way):

void FixedUpdate()
{
    Physics.gravity = new Vector3(0, -150, 0);    //This should be done in the inspector, under the edit > physics tab

    float xMove = (Input.GetButton("Horizontal") * MoveSpeed) / 56;
    float zMove = (Input.GetButton("Vertical") * MoveSpeed) * Time.deltaTime;
    Vector3 movement = new Vector3(xMove, 0, zMove);

    rb.AddForce(movement, ForceMode.VelocityChange);
  
    if(rb.position.y <= -5f)
        FindObjectOfType<EndGame>().gameover();
}

Similarly, in your Update() function, instead of checking when the player presses and releases the sprint button, you could just check to see if the sprint button is down or not, using Input.GetButton(). It could look something like this:

void Update()
{
    if (Input.GetKeyDown("space") && grounded)
        rb.AddForce(0, UpSpeed, 0 * Time.deltaTime, ForceMode.VelocityChange);    //Perhaps you want to use another ForceMode, or I'm forgetting something. Doesn't VelocityChange make the player shoot straight up instead of maintaining forward motion?

    if(Input.GetKey("left shift"))
    {
        if(rb.velocity.magnitude > 0.0f)  //This is the actual solution to your problem
        {
            //The rigidbody is moving, we're sprinting! Do stuff with stamina here
        }
        else
        {
            //We're holding shift but not moving, so refill stamina or do whatever here
        }
    }
    else
    {
          //We're not holding shift but we might be moving, do what you will with this (probably refill stamina too)
    }
}

Anyways, you can feel free to ignore my input on your input, as that’s largely irrelevant to your problem and if your script works, that’s all that really matters. But checking rigidbody magnitude before draining stamina will tell you if the player is moving or not.

1 Like

Hey thanks for your suggestions.
I tried rb.velocity.magnitude but am struggling to make it work. So as a test I did this.

   if (rb.velocity.magnitude > 0.0f)
        {
            moving = true;
            Debug.Log("moving now");
        }
        else
        {
            moving = false;
            Debug.Log("not moving");
        }

When I start the game, before my character even moves, “moving now” and “not moving” both enter into the console. It does not seem to be detecting when I am moving and not moving. What am I doing wrong?

Thanks,
J

Rigidbodies can be really fidgety, so instead of using 0 as your baseline for movement, try using a small number like 0.05 or even 0.01. Alternatively you could use Rigidbody.IsSleeping(), which should do the same thing.