How to spawn enemies at different locations and avoid overlapping each other

Hi everyone,

This is my first question here.

Heres my problem: I want to spawn enemies at different location (I have already managed to do that) but I want each enemy to spawn in a different location where it doesn’t overlap other enemies.

My code:

public class SpawnManager : MonoBehaviour {

    [SerializeField] GameObject[] asteroidPrefab;

    private float currentSpawn;

    void Start () {
       
    }
	
	// Update is called once per frame
	void Update () {
       
    }

    public void spawnAsteroids()
    {
      
        StartCoroutine(spawner());
        
    }

    IEnumerator spawner()
    {
        while (true)
        {
            Instantiate(asteroidPrefab[Random.Range(0, 3)], new Vector3(Random.Range(-7.0f, 7.0f), 7, 0), Quaternion.identity);
            yield return new WaitForSeconds(5.0f);
        }   
    }
}

This happens when the Random.range spawns enemies at close locations.

Is there a way that to avoid that?

Thank you.

Just to clarify, you just don’t want two enemies spawning at the same location right? Just making sure I understand your problem.

I’ve recently did an implementation of this. Basically whenever I instantiate my prefab, I store it in a list of existing instances ( instances.Add(newInstance);), and when it “dies”, I remove it from this list. Then before instantiating I first generate the position, and go through the list of instances to check if the position overlaps. If it does, I generate a new position. However, after a set number of tries I just stop, because if there is no space, I don’t want to get into an infinite loop.

In code:

public class SpawnManager : MonoBehaviour {

    [SerializeField] private AsteroidLogic[] asteroidPrefabs = null; // assign asteroid prefabs to it from Editor
    [SerializeField] private maxPositionRetries = 5;

    private List<AsteroidLogic> existingAsteroids = new List<AsteroidLogic>();
    public void AddAsteroid (AsteroidLogic value) { existingAsteroids.Add(value); }
    public void RemoveAsteroidLogic (AsteroidLogic value) { existingAsteroids.Remove(value); }

    public void Spawn () {
        AsteroidLogic asteroidPrefab = asteroidPrefabs[Random.Range(0, asteoidPrefabs.Length)];
        // probably check if the selected asteroidPrefab is not null!

         int numTries = 0;
         do {
             // generate a position, and check if it valid
             Vector3 position = new Vector3(Random.Range(-7.0f, 7.0f), 7, 0);
             if (IsValidPosition(position, asteroidPrefab.transform.localScale)) { // assign the second parameter (size) correctly, for example from the extents of the asteroid's collider, or get it from the AsteroidLogic
                 AsteroidLogic newAsteroid = Instantiate(asteroidPrefab, position, Quaternion.identity);
                 newAsteroid.SetSpawnManager(this);
                 break; // new asteroid generated, break out of loop
             }
         } while (numTries++ < maxPositionRetries);
    }

    private bool IsValidPosition (Vector3 positionToCheck, Vector3 objectSize) {
        for (int i = 0; i < existingAsteroids.Length; ++i) {
            AsteroidLogic asteroid = existingAsteroids*;*

Vector3 asteroidPosition = asteroid.transform.position;
Vector3 asteroidSize = asteroid.transform.localScale; // assign this correctly, e.g. from the collider’s extents

Vector3 positionDifference = positionToCheck - asteroidPosition;
Vector3 sizeSum = objectSize + asteroidSize;
// if the positions are less than the sum of the extents, they overlap; also check for z coordinate if you change that
if (Mathf.Abs(positionDifference.x) < sizeSum.x && Mathf.Abs(positionDifference.y) < sizeSum.y) { return false; }
}
return true;
}

}

public class AsteroidLogic : MonoBehaviour {

private SpawnManager spawnManager;

// automatically register itself when the manager is set
public void SetSpawnManager (SpawnManager value) {
spawnManager = value;
spawnManager.AddAsteroid(this);
}

// automatically unregister itself when it gets destroyed
private void OnDestroy () {
if (spawnManager != null) { spawnManager.RemoveAsteroid(this); }
}

}