Using WaitForSeconds in a For Loop?

Hey guys,

struggling with this, I know it’s something simple but I can’t work it out (If it’s not clear, I’m not very well versed with C#, so apologies)

so simply, we have a turret that’s rotating back and forth, the number of bullets it will shoot depends on the value of the ballsValue float from another script.

It works, but it spurts all of the balls out pretty much at once, or at least far too fast.

My thinking was if I could put it in a coroutine and add a Waitforseconds at the end of the for loop, it will wait that amount of time then loop back through, giving me a gap of 0.25 seconds between each shot.

This doesn’t work, all that happens is it just shoots one ball regardless of how many it’s told to shoot earlier.

probably a simple obvious fix, but can someone help?

IEnumerator ReleaseBallCoroutine()
    {
      
        for (int i = 0; i < ballSpawner.ballsValue; i++)
        {
           
            GameObject bulletClone = Instantiate(bullet, bulletSpawner.transform.position, bulletSpawner.transform.rotation);
                Rigidbody bulletRB = bulletClone.GetComponent<Rigidbody>();
                    bulletRB.AddForce(-bulletSpawner.transform.forward * m_Power, ForceMode.Force);
                      yield return new WaitForSeconds(0.25f);
                      
        }
    }

EDIT: Here’s the whole script

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

public class ReleaseScript : MonoBehaviour
{
   
    public GameObject bullet;
    public GameObject bulletSpawner;
    Rigidbody m_Rigidbody;
    public float m_Power = 5000f;
    void Start()
    {
       
    }
    void OnCollisionEnter(Collision col)
    {
        if(col.gameObject.tag == "Ball")
        {       
            print("Balls Released");
            Destroy(col.gameObject);
            //ReleaseBalls();
            StartCoroutine(ReleaseBallCoroutine());
            ballSpawner.ballsValue = 1;
        }
    }
   
    void Update()
    {
        if(Input.GetKeyDown("f"))
        {
            //ReleaseBalls();
            StartCoroutine(ReleaseBallCoroutine());
        }
    }

    // void ReleaseBalls()
    // {
       

    //     for (int i = 0; i < ballSpawner.ballsValue; i++)
    //     {
    //         GameObject bulletClone = Instantiate(bullet, bulletSpawner.transform.position, bulletSpawner.transform.rotation);
    //             Rigidbody bulletRB = bulletClone.GetComponent<Rigidbody>();
    //                 bulletRB.AddForce(-bulletSpawner.transform.forward * m_Power, ForceMode.Force);
                   
    //                     print("Relesing");

                       
    //     }

    // }


    IEnumerator ReleaseBallCoroutine()
    {
       
        for (int i = 0; i < ballSpawner.ballsValue; i++)
        {
            
            GameObject bulletClone = Instantiate(bullet, bulletSpawner.transform.position, bulletSpawner.transform.rotation);
                Rigidbody bulletRB = bulletClone.GetComponent<Rigidbody>();
                    bulletRB.AddForce(-bulletSpawner.transform.forward * m_Power, ForceMode.Force);
                      yield return new WaitForSeconds(0.25f); 
                       
        }
    }

       

}

Your thinking is perfectly reasonable. I’d guess something else is causing the issue here:
Try printing out the value of ballSpawner.ballsValue inside the coroutine. Perhaps that value is 1, which would lead to the loop only running once.

The other possibility is if your ReleaseScript object is being destroyed or deactivated while the coroutine is running, that will also stop the coroutine from running.

Actually on closer inspection I see this:

            StartCoroutine(ReleaseBallCoroutine());
            ballSpawner.ballsValue = 1;

You are setting ballsValue to 1 right here, which means the loop will only ever run one iteration.

Note that the order of execution here will be that your coroutine will run up until the first yield statement before StartCoroutine comes back. Then balls value will be set to 1. Then later your coroutine will resume and the for loop will end because ballsValue is 1 and i is 1.

1 Like

Ahh! I totally forgot that was there and that makes total sense!

Is there an easy way to say, if the for loop is complete, THEN set ballsValue to 1?

Many thanks!

1 Like

Of course, just as you said…

for (...) {
  ...
}
ballSpawner.ballsValue = 1;
1 Like

Oh wow, so simple!, I’m slightly embarrassed I didn’t know that.

Appreciate the help, thanks!

1 Like