'Destroy game objects one at a time, with time interval

I have created a procedurally generated 'tiled floor' in unity3d, using a block prefab asset and script as follows:

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

public class Wall : MonoBehaviour
{
    public GameObject block;
    public int width = 10;
    public int height = 10;
    public int timeDestroy = 1;
    List<GameObject> blockList = new List<GameObject>();
    

    void Start(){

        for (int y=0; y<height; ++y)
        {
            for (int x=0; x<width; ++x)
            {
                Vector3 offset = new Vector3(x, 0, y);
                GameObject hello= (GameObject)Instantiate(block, transform.position + offset, Quaternion.identity);
                blockList.Add(hello);
            }
        }
        
        StartCoroutine(SelfDestruct());

    }

    void Update()
    {
        SelfDestruct();
    }
    
    IEnumerator SelfDestruct()
    {
        yield return new WaitForSeconds(timeDestroy);
    
        Destroy(blockList[UnityEngine.Random.Range(0,(width*height))]);
        }
    }


When I run the game, one of the 100 blocks has been destroyed, but then nothing happens. From my script, I was expecting one block to destroy every second, as defined by: yield return new WaitForSeconds(timeDestroy); where int timeDestroy = 1;

and repeat until all the blocks are gone - game over. How can I change my script so the 100 gameObjects are destroyed one after another, until none are left?



Solution 1:[1]

you need to put your IEnumerator SelfDestruct(); in a while loop:

IEnumerator SelfDestruct()
{
    while (1<2)
    {
        Destroy(blockList[UnityEngine.Random.Range(0, (width * height))]);
        yield return new WaitForSeconds( timeDestroy );
    } 
}

that way it will resume destroying the blocks, and you need to remove the SelfDestruct(); in Update.

Ps. Thanks derHugo I have forgotten that ^^.

Solution 2:[2]

A couple of issues here

  • you start a coroutine once but it doesn't really wait for anything (only at the end). There is no repetition anywhere. You probably wanted to use a loop there

  • you call the SelfDestruct every frame within Update which will execute everything until the first yield!

  • you potentially try to destroy the same object multiple times since you never remove them from your list.

Actually the entire thing can be one single coroutine!

I would also use Linq OrderBy to randomize the order of blocks once and then simply iterate and destroy them one by one in already randomized order.

Something like e.g.

using System.Linq;
...

public class Wall : MonoBehaviour
{
    public GameObject block;
    public int width = 10;
    public int height = 10;
    public int timeDestroy = 1;
    
    // Yes this is valid and Unity will automatically
    // run this as a Coroutine!
    private IEnumerator Start()
    {
        // Don't even need this as a field only locally
        // already pre-allocate the needed amount
        var blockList = new List<GameObject>(height * width);

        for (var y = 0; y < height; ++y)
        {
            for (var x = 0; x < width; ++x)
            {
                var offset = new Vector3(x, 0, y);
                var newBlock = Instantiate(block, transform.position + offset, Quaternion.identity);
                blockList.Add(new Block);
            }
        }
        
        // shuffle the blocks once
        var randomizedBlocks = blockList.OrderBy(blockInstance => Random.value);
        // then simply iterate them in already randomized order
        foreach (var blockInstance in randomizedBlocks)
        {
            yield return new WaitForSeconds (timeDestroy);

            Destroy(blockInstance);
        }

        // Now you additionally also have direct control when they are all destroyed
        Debug.Log("All blocks have been destroyed!");
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2