1

I'm trying to implement cooldown for actions in my game - prevent same action from happening for some time. I.e. the character should jump only once in 3 seconds even if user presses "jump" button more often than that.

For some reason the jumpCooldown just gets stuck at like 2 and won't move on thus making my cooldown infinite.

In particular why jumpCooldown does not get to 0 and how to fix this code? I'm also open to other better approaches for implementing cooldown?

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

public class ExperminetMovement : MonoBehaviour
{
    static bool canJump = true;
    public float jumpCooldown = 3f;

    void Start() { }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space) && canJump)
        {
            canJump = CoolDownFunction();
        } 
    }
    public bool CoolDownFunction()
    {
        jumpCooldown -= Time.deltaTime;
        if (jumpCooldown <= 0)
        {
            jumpCooldown = 3f;
            return true;
        }
        return false;
    }
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • 1
    "Any help is appreciated" is not a question -- do you have a *specific* question? – Eric Lippert Jan 27 '20 at 18:25
  • "for some reason the time.deltatime just gets stuck at like 2 and won't move on. Thus making my cooldown infinite." – Anonymous User Jan 27 '20 at 18:36
  • "This code is much clearer and easier to understand" It may be for you, but the problem can still seem vague to others. Can you clarify what exactly you're trying to achieve with this code (e.g. only allowing the user to jump once every three seconds)? That may help others in helping you find a solution and avoid speculative answers. – devNull Jan 27 '20 at 19:16
  • @devNull yeah,but time.deltatime just gets stuck for some reason – Anonymous User Jan 27 '20 at 19:31
  • @EyalGelberg I've edited the post - please review. Note that I don't think "time.deltatime just gets stuck" is what you actually mean - I've edited it to "jumpCooldown just gets stuck at like 2" which is what *should* be happening with code you have. If you disagree with edit please don't just revert but edit in a similar way so it asks your question but does not include unrelated text as original version. – Alexei Levenkov Jan 27 '20 at 19:35
  • @Alexei Levenkov you explained it very well,that is exactly what I meant. I didn't know that the point it got stuck in has any value, but it sure is stuck at 2. Could you help me resolve this with your method? – Anonymous User Jan 27 '20 at 19:54
  • This is about [tag:c#], not [tag:unityscript]. – Ruzihm Feb 26 '20 at 19:13

2 Answers2

3

Your Update function is written as

if (Input.GetKeyDown(KeyCode.Space) && canJump)
{
    CoolDownFunction();
} 

This means that your cooldown is only being updated while the user is holding down the spacebar (Correction: For one frame. GetKey gets the current status). Instead, the jump cooldown time should be updated every frame (at least until canJump becomes true), and canJump should only be set to false if the user attempts to jump while canJump is true.

You need to separate out your jump cooldown from your jump request.

Also, once your user successfully jumps, canJump is set to false, so your CoolDownFunction will never run again, since your conditional will always be false.

Brian
  • 25,523
  • 18
  • 82
  • 173
  • I've tried tons of combinations that honestly I cannot look at this anymore with a collective mind. If you could write a semi-working example or just my code with your fixes I would really appreciate it. – Anonymous User Jan 27 '20 at 18:46
  • 1
    Personally I think better way would be to just remember last time of jump and compare... but indeed doing it every frame (as `deltaTime` is per-frame: "The completion time in seconds since the last frame") is indeed the right approach. – Alexei Levenkov Jan 27 '20 at 18:46
  • 1
    @EyalGelberg: Just copy the example from https://docs.unity3d.com/ScriptReference/Time-time.html . Note that this takes the approach recommended by Alexei, rather than the approach you attempted. – Brian Jan 27 '20 at 18:56
  • Just tried that @Brian,doesn't seem to work – Anonymous User Jan 27 '20 at 19:10
  • @Alexei Levenkov how would you go about doing that?I'm open for suggestions as long as it works – Anonymous User Jan 27 '20 at 19:11
  • @EyalGelberg the link Brian provided is exactly what I suggested. I don't see any simpler way of doing it (and can't see what you could have done so it "doesn't seem to work"). – Alexei Levenkov Jan 27 '20 at 19:25
  • 1
    `This means that your cooldown is only being updated while the user is holding down the spacebar` this is exactly **wrong**! It is called only **once** for each time the key is pressed! That is why it is always reduced by just a little bit... A while the button stays down would rather be `Input.GetKey(KeyCode.Space)` – derHugo Jan 27 '20 at 20:52
  • DerHugo is correct; GetKeyDown only returns true for one frame. Mind you, GetKey would still be wrong, for the reasons I discussed. – Brian Jan 27 '20 at 21:22
0

I'd suggest using IEnumerator for this along with

yield return new WaitForSeconds(jumpCooldown);

So something like:

using System.Collections;
using UnityEngine;

public class JumpExample : MonoBehaviour
{
    static bool canJump = true;
    public float jumpCooldown = 3f;


    void Update()
    {
        if (Input.GetKeyUp(KeyCode.Space) && canJump)
        {
            // Put your jump code here.
            StartCoroutine(CoolDownFunction());
        }
    }
    IEnumerator CoolDownFunction()
    {
        canJump = false;
        yield return new WaitForSeconds(jumpCooldown);
        canJump = true;
    }

}
Babipoki
  • 1
  • 3