Search code examples
c#unity-game-engine3dframe-rate

While loop timer with a bool that doesnt work Unity 3D


Using c#, im trying to fire a bullet every 3 seconds, so heres my workflow:

  1. fire button is pressed
  2. only fire if bool fireAgain is true
  3. set bool fireAgain = false
  4. start timer
  5. timer finished = bool fireAgain = true

When debugging it seems to all work properly, but when I test it, Im still able to shoot like 10 bullets a second. So somehow it just doesnt care about the bool FireAgain being false and shoots anyway even if according to debug bool fireAgain is false at that moment.

 public void Update()
    {
    //If  LEFT MouseButton is pressed, cast yer spells.
            if (fireAgain == true && Input.GetMouseButtonDown(0)) 
    {   
        StartCoroutine("LoopRotation");
        fireAgain = false;
        Debug.Log(fireAgain);
        Debug.Log("1 should be FALSE");
    }
        while (fireAgain == false && timer < bulletTime)
    {
        fireAgain = false;
        timer += Time.deltaTime;
        Debug.Log(timer);
        Debug.Log(bulletTime);
        Debug.Log(fireAgain);
        Debug.Log("2");
    } if (timer >= bulletTime)
    {
        fireAgain = true;
        timer = 0;
        //Debug.Log("Timer is finished");
        //Debug.Log(timer);
        Debug.Log(fireAgain);
        Debug.Log("3 should be true");
        

And here is the code for the Coroutine:

IEnumerator LoopRotation()
{
    pivot.transform.Rotate(triggerAngle,0,0);
        
        GameObject bullet = ObjectPooler.SharedInstance.GetPooledObject(); 
        if (bullet != null) {
                bullet.transform.position = SSpawn.transform.position;
                bullet.transform.rotation = SSpawn.transform.rotation;
                bullet.SetActive(true);
         }

    yield return new WaitForSeconds(.1f);
            pivot.transform.rotation = Quaternion.Slerp(transform.rotation, originalRotationValue, Time.deltaTime * rotationResetSpeed); 
    StopCoroutine("LoopRotation");
}

Enumerator LoopRotation was originally just to pivot the weapon a few degrees forwards and then backwards so it looks like a wack when you cast a spell, but now its also the shoot function, as it creates bullets.


Solution

  • You have a while loop within Update => this loop will completely run in one single frame => "immediately" will increase the timer until it is big enough => "immediately" will set your bool flag to true again!

    What you rather would do is e.g.

    public void Update()
    {
        //If  LEFT MouseButton is pressed, cast yer spells.
        if (fireAgain && Input.GetMouseButtonDown(0)) 
        {   
            StartCoroutine(LoopRotation());
            fireAgain = false;
            timer = 0;
            Debug.Log(fireAgain);
            Debug.Log("1 should be FALSE");
        }
        else if(timer < bulletTime)
        {
            // Only increase this ONCE per frame
            timer += Time.deltaTime;
            Debug.Log(timer);
            Debug.Log(bulletTime);
            Debug.Log(fireAgain);
            Debug.Log("2");
    
            if(timer >= bulletTime)
            {
                fireAgain = true;
                timer = 0;
                //Debug.Log("Timer is finished");
                //Debug.Log(timer);
                Debug.Log(fireAgain);
                Debug.Log("3 should be true");
            }
        }
    }
    

    As alternative you could use Invoke and skip the timer in Update completely:

    public void Update()
    {
        //If  LEFT MouseButton is pressed, cast yer spells.
        if (fireAgain && Input.GetMouseButtonDown(0)) 
        {   
            StartCoroutine(LoopRotation());
            fireAgain = false;
            Invoke (nameof(AllowFireAgain), bulletTme);
        }
    }
    
    private void AllowFireAgain()
    {
        fireAgain = true;
    }
    

    Note that your Coroutine doesn't make much sense to me. You are only rotating exactly once and only a really small amount.

    The StopCoroutine in the end is unnecessary.


    Also note: for debugging fine but later you should avoid to have Debug.Log running every frame in a built application. Even though the user doesn't see it the log is still created into the player log file and causes quite an amount of overhead.