Search code examples
c#unity-game-enginefor-looptimer

How to wait in for loop for x second c# - unity


I just started using Unity and I want to build the following function: Currently I press a button which spawns an asteroid outside of the screen, then the asteroid moves through the screen from right to left and finally I destroy the asteroid out of screen. All this is working already. But now I want to change the button function so that it spawns more asteroids delayed by a few seconds. And I don't know how to do that. My Code looks like this at the moment:

public class ButtonSkript : MonoBehaviour
{       
    private Vector3 spawnPosition = new Vector3(15, 0, 0);
    public GameObject planet_001Prefab;
    public GameObject planet_011Prefab; // not in use
    public GameObject planet_017Prefab; // not in use
    public GameObject planet_079Prefab; // not in use
    

    public void ShowJourney()
    {
        int[] asteroids_array = {27, 569, 1293, 37};
        int[] material_type_array = {0, 2, 1, 3}; // not in use
        
        for (int i  = 0; i < asteroids_array.Length; i++) {
            GameObject a = Instantiate(planet_001Prefab);
            a.transform.position = spawnPosition;
        
            Destroy(a, 3);

            // wait for 3 seconds
        }
    }
}


public class Translate : MonoBehaviour
{
    public float speed = 10.0f;


    // Update is called once per frame
    void Update()
    {
        moveAsteroid(new Vector2(-1, 0));
    }
    
    void moveAsteroid(Vector2 direction)
    {
        transform.Translate(direction * speed * Time.deltaTime);
    }
}

I already tried System.Threading.Thread.Sleep(3000); and I also tryed to build a timer with IEnumarate and yield return new waitForSeconds(3.0f); but both things are not working or I didn't implement it correctly.

It is probably an easy question, but I can't figure it out on my own.

Thanks for the help :)


Solution

  • The StartCoroutine method is a little like a fire-and-forget method. It’ll start a new coroutine, without actually waiting to see what the coroutine is doing. So, your initial attempt at looping through and starting ‘n’ coroutines is doing exactly that - starting 4 new coroutines all at the same time.

    A potential fix in this situation might be:

    int[] asteroids_array = {27, 569, 1293, 37};
    int[] material_type_array = {0, 2, 1, 3}; // not in use
    
    public void ShowJourney()
    {
        StartCoroutine(Spawn());
    }
    
    IEnumerator Spawn()
    {
        for (int i  = 0; i < asteroids_array.Length; i++)
        {
            var a = Instantiate(planet_001Prefab);
            a.transform.position = spawnPosition;
            Destroy(a, 3); // could be here, or after the WaitForSeconds.
            yield return new WaitForSeconds(3);
        }
    }
    

    Note that there’s no check to see if the coroutine is running, so if you have a button attached to ShowJourney you might still end up with lots of coroutines running.

    If each asteroid followed your logic, you could also just reposition the asteroid instead of creating a new one. For example:

    IEnumerator Spawn()
    {
        var a = Instantiate(planet_001Prefab);
        a.transform.position = spawnPosition;
        for (int i  = 0; i < asteroids_array.Length; i++)
        {
            yield return new WaitForSeconds(3);
            a.transform.position = spawnPosition;
        }
        Destroy(a);
    }
    

    But this just illustrates that there’s often many ways to accomplish the outcome you’re looking for.