Savourai
Savourai

Reputation: 11

Can't make cooldown work, bugs out and isn't working properly

So I am making a VR game and what I want to do is, as soon as I press the trigger on the joystick the "sword" gets activated and can stay activated for 1 second, after that it has a cooldown of 1 second also in which it cannot get activated, and then it resets. I thought it would be simple but I can't for the life of me make it work.

Here's the code:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;

public class Sword : MonoBehaviour
{
    public SteamVR_Action_Boolean ActivateSword;
    public SteamVR_Input_Sources handType;
    private bool IsSwordActivated = false;
    private bool canSwordGetActivated = true;
    private bool cooldownStart = false;
    public Material activatedSword;
    public Material defaultSword;
    public float timeStamp;
    public float timer = 0;
    public float cooldown = 2;

    void Start()
    {
        ActivateSword.AddOnStateDownListener(TriggerDown, handType);
        ActivateSword.AddOnStateUpListener(TriggerUp, handType);
        timeStamp = Time.time;
    }

    public void TriggerUp(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
    {

            Debug.Log("Trigger is up");
            IsSwordActivated = false;
            this.GetComponent<MeshRenderer>().material = defaultSword;

    }
    public void TriggerDown(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
    {
        if (canSwordGetActivated == true)
        {
            Debug.Log("Trigger is down");
            IsSwordActivated = true;
            cooldownStart = true;
            this.GetComponent<MeshRenderer>().material = activatedSword;
        }


    }



    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Enemy"))
        {
            if (IsSwordActivated == true)
            {
                Destroy(collision.gameObject);
            }
        }

    }
    private void Update()
    {
        //if (timeStamp <= Time.time)
        //{
        //    if (IsSwordActivated == true)
        //    {
        //        timeStamp += 2;
        //        canSwordGetActivated = false;
        //        Debug.Log("test");
        //    }
        //}
        if (cooldownStart == true)
        {
            timer += Time.deltaTime;
            cooldown -= Time.deltaTime;
            if (timer >= 1f)
            {
                this.GetComponent<MeshRenderer>().material = defaultSword;
                IsSwordActivated = false;
                timer = 0;
            }
            if (timer == 0)
            {
                canSwordGetActivated = false;
            }
            if (cooldown <= 1f)
            {
                canSwordGetActivated = false;
            }
            if (cooldown <= 0)
            {
                cooldown = 2f;
                canSwordGetActivated = true;
                cooldownStart = false;
            }

        }

    }
}


Upvotes: 0

Views: 71

Answers (2)

Jan Thom&#228;
Jan Thom&#228;

Reputation: 13624

One simple way of doing this would be a coroutine:

class Sword {
   private bool isCoolingDown;

   public void Swing() {
       if (isCoolingDown) {
           Debug.Log("Sorry, cooling down right now");
           return;
       }

       StartCoroutine(DoSwingSword());

   }

   private IEnumerator DoSwingSword() {
       isCoolingDown = true;
       yield return new WaitForSeconds(1);
       isCoolingDown = false;
   }
}

This will use a bool to track if you are in cooled down state and automatically reset this bool after one second, without you having to track Time.deltaTime. You can then wrap the rest of your logic around this bool.

Upvotes: 0

derHugo
derHugo

Reputation: 90629

You should not use Update but a Coroutine for that. Especially the "cooldown" should run independently from the "timer".

// Not needed
//private bool cooldownStart = false;
//public float timer = 0;

// reference this already via the Inspector if possible
[SerializeField] private MeshRenderer _meshRenderer;

[SerializeField] private float cooldownTime = 1;
[SerializeField] private float maxEnabledTime = 1;

// Otherwise get it only ONCE on runtime
private void Awake()
{
    if(!_meshRenderer) _meshRenderer = GetComponent<MeshRenderer>();
}

public void TriggerUp(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
{
    Debug.Log("Trigger is up");

    // stop the timeout
    StopAllCoroutines();

    // disable sword and start cooldown
    StartCoroutine(SwordCooldown());
}

public void TriggerDown(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
{
    if(IsSwordActivated) return;
    if (!canSwordGetActivated) return;

    Debug.Log("Trigger is down");

    // start timeout
    StartCoroutine(SwordEnabledTimer());
}

///<summary>
/// Disables sword and Runs cooldown before sword can be enabled again
///<summary>
private IEnumerator SwordCooldown()
{
    canSwordGetActivated = false;

    IsSwordActivated = false;
    _meshRenderer.material = defaultSword;

    yield return new WaitForSeconds(cooldownTime);

    canSwordGetActivated = true;
}

///<summary>
/// Disables the sword and jumps to cooldown after it was enabled for too long
///<summary>
private IEnumerator SwordEnabledTimer()
{
    canSwordGetActivated = false;

    yield return new WaitForSeconds(maxEnabledTime);

    StartCoroutine(SwordCooldown());
}

See WaitForSeconds


Sideeffect/Advantage:

Coroutines are often better read- and maintainable and more flexible then polling states in Update!

For example You can now very simple extend both routines and add a progress display for both like e.g.

private IEnumerator SwordCooldown()
{
    canSwordGetActivated = false;

    IsSwordActivated = false;
    _meshRenderer.material = defaultSword;

    var timePassed = 0f;
    while(timePassed < cooldownTime)
    {
        var cooldownProgress = timePassed / cooldownTime;

        // do something with the cooldownProgress value 0-1

        timePassed += Mathf.Min(Time.deltaTime, cooldownTime - timePassed);
        yield return null;
    }

    canSwordGetActivated = true;
}

Upvotes: 2

Related Questions