How could I instantiate several objects in a row?

I’m wanting to instantiate a gameobject upon enemy death several times, every .2f seconds.

I’m getting screwed up figuring out whether to do a for loop or a coroutine. What would be the best way to pull this off?

For the visual, essentially it’s like a bomb chain effect so I’ll want to instantiate an object X times in random positions.

Thanks!

Well you just yield a delay in a co-routine loop. It can be any kind of loop. Like this:

public IEnumerator BombChain(int bombCount, float delay)
{
    for (int i = 0; i < bombCount; i++)
    {
       //spawn bombs, etc
        yield return new WaitForSeconds(delay);
    }
}
2 Likes

A for loop will instantiate everything at the same time. So all 3 objects unless you iterate once per frame. But then you may aswell have just thrown your death position into a list of a manager script and handled what to do about instantiating when that list has content and it’s elements are being checked.

It’s a co-routine with a delay between loops, so… no it won’t?

did I say something wrong?

So I ended up doing this (on a manager script because I destroy the enemy after running the bomb chain ienumerator).

Here’s what I ended up writing:

    private void randomizeBombPositionInts()
    {
        randomX = Random.Range(-1.5f, 1.5f);
        randomY = Random.Range(-1.5f, 1.5f);
    }


    public IEnumerator BombChain(Vector3 enemyPosition)
    {

        for (int i = 0; i < magicBomb; i++)
        {
            Debug.Log("Bomb spawned");
            randomizeBombPositionInts();

            Instantiate(magicBombItem, new Vector2(enemyPosition.x + randomX, enemyPosition.y + randomY), transform.rotation);
            yield return new WaitForSeconds(.1f);
        }
    }

The issue I’m encountering is that it’s only running the for loop once. I have debugged to confirm this, and I can also confirm that the “magicBomb” int is 3 when running, so it should be dropping 3 bombs right?

What object is actually starting this co-routine? Depending on how you’ve done it, the object you’re destroying could still be the monobehaviour this co-routine is attached to; thus it will only perform one execution before being destroyed and killing the co-routine.

An example of how’s being called would be good.

Sure yeah, so the script above is on a manager called ItemTracker and the coroutine is being called from an enemy before it dies. That’s here:

            if (ItemTracker.instance.magicBomb > 0)
            {
                StartCoroutine(ItemTracker.instance.BombChain(transform.position));
            }

I understand your concern about the enemy being destroyed, but as far as I’m aware all I’m doing is starting the coroutine and setting the position of the bomb spawn from the enemy before destroying it. Everything else should be playing out on the ItemTracker without issue.

Does that make sense?

No you’re doing exactly what I said would cause the issue. You’re starting the co-routine from the object being destroyed, tying the lifetime of the co-routine to it. Thus, when the enemy is destroyed, the co-routine is killed.

Instead, do this:

if (ItemTracker.instance.magicBomb > 0)
{
    ItemTracker instance = ItemTracker.instance;
    instance.StartCoroutine(instance.BombChain(transform.position));
}

Or, give your manager a static method that starts up the co-routine itself, rather than the enemy being in charge of this logic themselves.

You can avoid all this ownership and lifetime noise by using a simple “do something later” script.

I use my CallAfterDelay class for delayed action.

See usage notes at bottom below gist code.

In your case you would issue CallAfterDelay instances for each of the bombs with ever-increasing delays, then you can just go away fearlessly and as each CallAfterDelay matures, the spawn will happen, something like:

using UnityEngine;

public class MakeLineOfBombs : MonoBehaviour
{
    void Start()
    {
        for (int i = 0; i < 10; i++)
        {
            Vector3 spawnPosition = Vector3.right * (i - 5);

            float time = i * 0.25f;

            // @kurtdekker... get this from:
            // https://gist.github.com/kurtdekker/0da9a9721c15bd3af1d2ced0a367e24e
            CallAfterDelay.Create( time, () => {
                var bomb = GameObject.CreatePrimitive( PrimitiveType.Sphere);
                bomb.transform.position = spawnPosition;
            });
        }

        // we can happily go away now
        Destroy(gameObject);
    }
}

So this wouldn’t work for some reason - the ItemTracker is already an instance of itself, so should be good there.

Thank you! I ended up doing a variation of this that worked.

I created a “BombChainCreator” script & prefab, and just had that spawn at each enemy’s death, then from there instantiate the bombs from that script in the position of that new frefab object. It’s working great now!

1 Like