How do I use Couroutines for spawning and spawn certain amount of enemy AI in the scene?

by Freddy   Last Updated August 21, 2016 08:05 AM

I have made a spawn function for spawning enemy AIs, and it didn't work well in my scene. I have the enemy AIs spawning in the update function, and it initially works fine, but it's spawning too many enemy AIs in the scene.

I want to do 3 6 9 enemy AIs at a time, and not spawn too many at a time. Here is my script :

using UnityEngine;
using System.Collections;

public class EnemiesSpawner : MonoBehaviour 
{
    public GameObject enemy;
    public Transform [] spawnPoints;
    public float spawnTime = 20f;
    public Vector3 spawnValues;

    void Start () 
    {
        // Call the "Spawn" function every 10 seconds
        InvokeRepeating("Spawn", spawnTime, spawnTime);
    }

    void Update () 
    {
        int spawnPointIndex = Random.Range (0, spawnPoints.Length); 

        for(int spawnCount = spawnPoints.Length - 1 ; spawnCount >= 0 ; --spawnCount)
        {
            Instantiate(enemy, spawnPoints[spawnPointIndex].position, 
                spawnPoints[spawnPointIndex].rotation);
        }

        Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x),
            1, Random.Range (-spawnValues.z, -spawnValues.z));
    }
}


Answers 1


Limiting how many of a certain object you spawn can be quite simple. You could either instantiate them into an array, and check the size of the array before loading each AI, or you could simply keep a count of how many AIs are in play, directly.

Keeping Count

If you only wish to keep a simple count, I would probably recommend using a simple int variable to keep a record of the current number. If you have to manage the enemy AI currently in play, it might be better to set up a List<> reference, to hold a reference to all of your current enemy AI in play.

Using a list to store your enemy objects

If you use a List<> array to store all of your enemy AI, you could check its size to determine how many enemy AI are in play prior to spawning more enemy AI. It is also fairly easy to remove the enemy AI from this list as you need to.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;  // LIST LIBRARY: DON'T FORGET IT

public class EnemiesSpawner : MonoBehaviour
{
    public List<GameObject> enemyArray;
    public int enemyMax = 9;

    void Start()
    {
        enemyArray = new List<GameObject>(); // DON'T FORGET TO INITIALISE
    }

    void SpawnEnemy()
    {
        if(enemyArray.Count < enemyMax)
        {
            GameObject enemy = new GameObject();

            // Instantiate and set up your enemy

            enemyArray.Add(enemy);
        }
        else
        {
            Debug.Log("WARNING: Trying to load an enemy. Too many enemies: | Current: " 
                + enemyArray.Count + " | Maximum allowed: " + enemyMax);
        }
    }
}

It might be worth storing your enemy AI as the script type, not the GameObject type. Say your enemy AI use the script EnemyAI; storing them using List<EnemyAI>() enemyList still lets you reference the GameObject with enemyList[i].gameObject. However, you also have direct access to any public functions you have on your EnemyAI script. This is especially useful if you ever need to iterate through your EnemyAI objects and perform a specific function.

Manually keeping count

Another alternative, if you do not wish to keep a reference to all of your enemy AI in play, is to simply keep a manual count in the spawner.

float maxEnemies = 9;
float currentEnemies = 0;

void SpawnEnemy()
{
    if(currentEnemies < enemyMax)
    {
        // Instantiate and set up your enemy

        currentEnemies ++;
    }
    else
    {
        Debug.Log("WARNING: Trying to load an enemy. Too many enemies: | Current: " 
            + currentEnemies + " | Maximum allowed: " + maxEnemies);
    }
}

Reporting back to EnemiesSpawner

Of course, your still going to have to report back to your EnemiesSpawner script, whenever you destroy an enemy AI. If you do not, you will not be able to spawn any more enemy AI once you reach the maximum count - even when the other enemy AI are removed from play. If you only have a single instance of EnemiesSpawner, a static self-reference is probably the best option. Alternativley, you could set up a reference to the parent EnemiesSpawner in the EnemyAI script, itself.

Static self-reference

A static self-reference is far easier to communicate with, but it has its limitations. For one, it requires the assumption that there is only one instance of EnemiesSpawner in place. If there are multiple EnemiesSpawner scripts in operation, this will have undesirable results, and will not work. Once you set up the reference, any script can access your EnemiesSpawner from anywhere, using this reference. While it is a shortcut, it can lead to other undesirable consequences, as a result.

public class EnemiesSpawner: MonoBehaviour
{
    public static EnemiesSpawner selfReference;
    public int currentEnemies;

    void Start()
    {
        selfReference = this
    }
}

public class EnemyAI : Monobehaviour
{
    void RemoveEnemy()
    {
        EnemiesSpawner.selfReference.currentEnemies --;
        Destroy(this);
    }
}

Providing a reference to the parent EnemiesSpawner when instantiating EnemyAI

If you have multiple EnemiesSpawner scripts in play, or just want a more secure reference for communicating back from the enemies, providing a reference directly to the EnemyAI is a good option.

public class EnemyAI : Monobehaviour
{
    EnemiesSpawner parentSpawner;

    // the option to pass in the EnemiesSpawner on instantiation
    // EnemyAI = new EnemyAI(this) from inside EnemiesSpawner
    public EnemyAI(EnemiesSpawner parentSpawner)
    {
        this.parentSpawner = parentSpawner;
    }

    void RemoveEnemy()
    {
        parentSpawner.currentEnemies --;
        Destroy(this);
    }

    void SetParentSpawner(EnemiesSpawner parentSpawner)
    {
        this.parentSpawner = parentSpawner;
    }
}

public class EnemiesSpawner: MonoBehaviour
{
    public int currentEnemies;

    void SpawnEnemy()
    {
        // after checking that we actually can spawn an enemy..
        GameObject enemy;
        // instantiate enemy
        enemy.GetComponent<EnemyAI>().SetParentSpawner(this);
    }
}
Timelord64
Timelord64
August 21, 2016 02:35 AM

Related Questions



Fade out / fade in scene w/ loading screen

Updated April 29, 2016 08:05 AM

How to await async operations / coroutines?

Updated July 26, 2016 08:05 AM

How do I find the location of a GameObject in C#

Updated March 18, 2016 08:05 AM

Roatating a Game Object downward

Updated April 15, 2016 08:05 AM