Spawn enemies so they aren't instantiated on top of each other (C#)

Hello my fellow great Unites! I have an enemy spawn system that spawns out enemies using Ienumerator inside a set of borders. Now the only problem is that the enemies will sometimes spawn out on the player, or another object…

How can I fix this problem? Using a for loop?

Here’s the code:

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 public class EnemySpawn : MonoBehaviour 
 {
     // EnemyPrefabs
     public GameObject EnemyBouncingPrefab;
     public GameObject EnemyGrowerPrefab;
     public GameObject EnemyMinePrefab;
 
     //Show where spawn is prefab
     public GameObject showEnemySpawn;
     public GameObject showEnemyFlyBySpawn;
     public GameObject showEnemyGrowerSpawn;
     public GameObject showEnemyMineSpawn;
 
 
     // Array of spawn points 
     public Transform[] spawnPointsEnemyFollow; 
     public Transform[] spawnPointsEnemyExplode;
     public Transform[] spawnPointsEnemyFlyBy;
     
     // Borders
     public Transform borderTop;
     public Transform borderBottom;
     public Transform borderLeft;
     public Transform borderRight;
     
 
     //Used to put active enemies in a list
     public static List<GameObject> activeEnemies;
 
     void Start () 
     {
         // Starts a coroutine function for spawning bouncing enemies and fly by enemy
         StartCoroutine(SpawnBouncingEnemy());
         StartCoroutine(SpawnGrowerEnemy());
         StartCoroutine(SpawnEnemyFlyBy());
         StartCoroutine(SpawnMineEnemy());
     }
 
     void Awake()
     {
         // Create the list
         activeEnemies = new List<GameObject>();
 
     }
     
     // Spawn a Bouncing enemy
     IEnumerator SpawnBouncingEnemy() 
     {
         //Wait 3 to 5 seconds when game starts to spawn a ball
         yield return new WaitForSeconds(Random.Range(1, 3));
 
         while(true)
         {
             //Calls the function to set random position
             Vector2 spawnPoint = RandomPointWithinBorders();
             
             // Show spawn location for one second
             Object marker = Instantiate(showEnemySpawn, spawnPoint, Quaternion.identity);
             yield return new WaitForSeconds(1);
             Destroy(marker);
             
             // Spawn enemy
             GameObject newEnemy = (GameObject) Instantiate(EnemyBouncingPrefab, spawnPoint, Quaternion.identity);
 
             activeEnemies.Add(newEnemy);
 
             yield return new WaitForSeconds(Random.Range(4, 6));
 
         }
         
     }    
 
     // Spawn a Grower enemy
     IEnumerator SpawnGrowerEnemy() 
     {
         //Wait 3 to 5 seconds when game starts to spawn a "grower"
         yield return new WaitForSeconds(Random.Range(20, 40));
         
         while(true)
         {
             //Calls the function to set random position
             Vector2 spawnPoint = RandomPointWithinBorders();
             
             // Show spawn location for one second
             Object marker = Instantiate(showEnemyGrowerSpawn, spawnPoint, Quaternion.identity);
             yield return new WaitForSeconds(1);
             Destroy(marker);
             
             // Spawn enemy
             GameObject newEnemy = (GameObject) Instantiate(EnemyGrowerPrefab, spawnPoint, Quaternion.identity);
             
             activeEnemies.Add(newEnemy);
             
             yield return new WaitForSeconds(Random.Range(20, 50));
             
         }
         
     }
 
     // Spawn a Mine enemy
     IEnumerator SpawnMineEnemy() 
     {
         //Wait 40 to 60 seconds when game starts to spawn a "Mine_enemy"
         yield return new WaitForSeconds(Random.Range(45, 60));
         
         while(true)
         {
             //Calls the function to set random position
             Vector2 spawnPoint = RandomPointWithinBorders();
             
             // Show spawn location for one second
             Object marker = Instantiate(showEnemyMineSpawn, spawnPoint, Quaternion.identity);
             yield return new WaitForSeconds(2);
             Destroy(marker);
             
             // Spawn enemy
             GameObject newEnemy = (GameObject) Instantiate(EnemyMinePrefab, spawnPoint, Quaternion.identity);
             
             activeEnemies.Add(newEnemy);
             
             yield return new WaitForSeconds(Random.Range(50, 60));
             
         }
         
     }
 
     public Vector2 RandomPointWithinBorders()
     {
         //Code that will spawn a bouncing ball and ShowSpawn at a random position inside the borders 
         Vector2 random = new Vector2();
         random.x = (int)Random.Range(borderLeft.position.x, borderRight.position.x);
         random.y = (int)Random.Range(borderBottom.position.y, borderTop.position.y);
         return random;
     }
 }

The usual way to solve this problem is to set up multiple spawn points in your level. You place them manually in the editor, mark them in a special way (a tag, or more likely you write up a “SpawnPoint” component), then when spawning your objects you keep track of which spawn point has been used, and spawn the object at an unused spawn point’s location.

In order to reuse the spawn points, you could also give them a simple box collider, set up as a trigger. This way once you spawn an object at this location, the spawned object enters the trigger; once the spawned object exits the trigger, you know you can use the spawn point again.

You might also want to have an enum value on the SpawnPoint component to decide if it’s a player spawn point, an AI spawn point, etc…

Use Physics.OverlapSphere to check the space before Instantiate.