C# function to reset a bool after a specified time

So i have an ‘Attacks’ script that uses a spell or attack when the mouse is pressed. Each attack has a float attack speed and a bool. When a spell is used, i launch the spell then invoke a function by the attack speed like this:

karmaOffCD  = false;
Invoke("karmaCDReset", karmaAS);
void karmaCDReset(){
        karmaOffCD = true;
    }

There are going to be a lot of spells and attacks that work this way, so i was wondering instead of creating a new function for resetting the cooldown for each spell/attack, is it possible to write a function that takes in any bool and attack speed, and turns that bool to true after a certain amount of time (attack speed)?

Cheers.

If your code is running in a MonoBehaviour, you can solve this with a coroutine:

private Coroutine karmaDelay;
private bool karmaOffCD;
private float karmaCooldown;

private void KarmaCDReset() {
    karmaOffCD = true;

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

    IEnumerator KarmaDelayRoutine() {
        yield return new WaitForSeconds(karmaCooldown);
        karmaOffCD = false;
    }
}

Nesting the coroutine is only available in C# 7, which means Unity 2018.3 or later.

I would recommend building some bool-on-cooldown wrapper, though. That’ll make making changes to how cooldowns work easier, and the code easier to read.

// Cooldown:
public class Cooldown {
    public float cooldownDuration;
    private float cooldownFinishedAtTime;

    public bool OffCooldown {
        get => Time.time >= cooldownFinishedAtTime;
        set => cooldownFinishedAtTime = Time.time + cooldownDuration;
    }
}

// use

public CooldownBool abilityCooldown = new CooldownBool { cooldownDuration = 5f };

public void TryToUseSomeAbility() {
    if (abilityCooldown.OffCooldown) {
        abilityCooldown.OffCooldown = false;
        UseSomeAbility();
    }
}

You could alternatively just use a float directly instead:

public float abilityCooldownDuration;
public float abilityOffCooldownAtTime;

public void TryToUseSomeAbility() {
    if (abilityOffCooldownAtTime > Time.time) {
        abilityOffCooldownAtTime = Time.time + abilityCooldownDuration;
        UseSomeAbility();
    }
}

Though having it as a thing could make it easier to reason about. Depends on your style.

This is a way to use inline functions instead of seperate functions.

public class YieldFunc : WaitUtils {

    public bool exampleBoolean;

    void Start()
    {
        exampleBoolean = true;
        WaitAndDo(1.0f, () => exampleBoolean = false);
    }
}

For this to work you’ll have to extend the class you’re using to WaitUtils, or move the functions from WaitUtils into the class you want to use.

public abstract class WaitUtils : MonoBehaviour {

    public Coroutine WaitAndDo(float timeInSeconds, Action action)
    {
        return StartCoroutine(Execute(timeInSeconds, action));
    }

    private IEnumerator Execute(float timeInSeconds, Action action)
    {
        yield return new WaitForSeconds(timeInSeconds);
        if (Application.isPlaying) action();
    }

}
1 Like

You better not to relay on invoke/coroutines and create separate game object for this because object launched attack might be destroyed before attack reaches its target and all coroutines/invokes in it’s script will be terminated. It’s better to create separate game object for this sake like a delayed actions manager or rely on the scripts on the attack effect itself be it arrow, fireball or whatever.

1 Like

This is perfect, thankyou!

The script is on my Player object so no problems there!

So your enemies won’t have range attacks at all or you plan to do it with another script? Also, player may launch an attack and die in next frame, will it’s object be destroyed or not?

They already do have ranged attacks. I’m confused as to what you mean? When the Player launches an attack it spawns a completely different GameObject which handles the attack. Why would this script affect it?

I was thinking your attack script belongs to attacker object, but if it’s on the attack object, then everything is okay

1 Like