Foreach skips IEnumerator method - Destroying objects after time

Hi,
I have object that contain 6 cubes in a row as his children. I want to slowly destroy them one by one after some time, but my code doesnt seem to work. It totaly skips the Clear Method and continues in the foreach loop. Any advices pls ? :slight_smile:

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

public class podlahaScript : MonoBehaviour
{

    void Start ()
    {
        foreach (Transform child in transform)
        {
            GameObject novy = child.gameObject;
            Clear(novy);
        }
    }

    IEnumerator Clear(GameObject novy)
    {
        yield return new WaitForSeconds(1);
        Destroy(novy);
    }
}

Your Clear method returns an IEnumerator object. Seems like you don’t have a clear idea of what that means.

IEnumerator is a thing that can be used to read the data of a collection.

Initially, the enumerator is positioned before the first element in the collection. You must call the MoveNext method to advance the enumerator to the first element

Without necessarily knowing it, you take advantage of this for example every time you use a foreach loop.

There is nothing magical or Unity specific about IEnumerators. You can use a method that returns an IEnumerator like this for example

IEnumerator Numbers() {
     yield return 1;
     yield return 2;
     yield return 3;
}
 ...
IEnumerator num = Numbers();
while (num.MoveNext()) {
     Debug.Log(num.Current.ToString());
}

// prints out 1 2 3

You don’t call MoveNext() on your enumerator so it never advances past the first yield. Furthermore WaitForSeconds doesn’t do anything by itself.

But when you start a coroutine and give it an IEnumerator that returns a WaitForSeconds, the coroutine uses this returned object as an instruction to call MoveNext after that delay.

You should be able to fix your code by changing

int i = 1;
foreach (Transform child in transform)
{
     GameObject novy = child.gameObject;
     StartCoroutine(Clear(novy), i++);
}
 
IEnumerator Clear(GameObject novy, float delay)
 {
     yield return new WaitForSeconds(delay);
     Destroy(novy);
 }

If the clear method only destroys the object, you could just use the overload of Destroy() that takes a second parameter (delay)

int i = 1;
foreach (Transform child in transform)
{
     GameObject novy = child.gameObject;
     Destroy(novy, i++);
}

In general you just have to be careful not to remove or add objects to the IEnumerable (transform) while the foreach is still running on it. That will throw an error. Can’t remember if Destroy() without a delay will cause it since it’s not instant anyways. If you set a delay, it won’t.

This should help:

void Start()
{
    StartCoroutine(Clear(transform));
}

IEnumerator Clear(Transform novy)
{
    foreach(Transform child in novy){
        yield return new WaitForSeconds(1);
        Destroy(child.gameObject);
    }
}

There two problems with your code:

  1. Coroutine is not called as it should be called (StartCoroutine…).
  2. Every time you call a coroutine, you make it wait for 1 second before Destroying the object. But there is no delay between each individual call. So all coroutines are called instantly one after other, they wait for 1 second (together) and after that start deleting the respective gameobjects (almost together at same time).

P.S. : This code is not tested. But should work.