Home > Net >  Destroy game objects one at a time, with time interval
Destroy game objects one at a time, with time interval

Time:04-11

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?

CodePudding user response:

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 ^^.

CodePudding user response:

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!");
    }
}
  • Related