- Home /
how can i avoid objects spawning on the same Spawn points twice in a row
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class WaveSpawner : MonoBehaviour { public enum SpawnState {Spawning, Waiting, Counting}
[System.Serializable]
public class Wave
{
public string name;
public Transform enemy;
public Transform hostage;
public int count;
public int hostageCount;
public float rate;
}
public Wave[] waves;
private int nextWave = 0;
public Transform [] spawnPoints;
public float timeBetweenWaves = 5f;
public float waveCountdown;
private float searchCoundown = 1f;
private SpawnState state = SpawnState.Counting;
// Start is called before the first frame update
void Start()
{
waveCountdown = timeBetweenWaves;
if(spawnPoints.Length == 0)
{
Debug.LogError("No spawn points referenced");
}
}
// Update is called once per frame
void Update()
{
if (state == SpawnState.Waiting)
{
//Check if enemies are still alive
if(!EnemyIsAlive())
{
//Begin a new round
WaveCompleted();
}
else
{
return;
}
}
if(waveCountdown <= 0)
{
if(state != SpawnState.Spawning)
{
//Start spawning wave
StartCoroutine(SpawnWave (waves[nextWave]));
}
}
else
{
waveCountdown -= Time.deltaTime;
}
}
void WaveCompleted()
{
Debug.Log("Wave Completed");
state = SpawnState.Counting;
waveCountdown = timeBetweenWaves;
if(nextWave + 1 > waves.Length -1)
{
nextWave = 0;
Debug.Log("ALL WAVES COMPLETE! Looping...");
}
else
{
nextWave++;
}
}
bool EnemyIsAlive()
{
searchCoundown -= Time.deltaTime;
if(searchCoundown <= 0f)
{
searchCoundown = 1f;
if(GameObject.FindGameObjectWithTag("Enemy") == null)
{
return false;
}
}
return true;
}
IEnumerator SpawnWave (Wave _wave)
{
Debug.Log("Spawning Wave: " + _wave.name);
state = SpawnState.Spawning;
//Spawn
for(int i = 0; i < _wave.count; i++)
{
SpawnEnemy(_wave.enemy);
yield return new WaitForSeconds(1f/_wave.rate); //wait for x seconds
}
for(int i = 0; i < _wave.hostageCount; i++)
{
SpawnEnemy(_wave.hostage);
// yield return new WaitForSeconds(1f/_wave.rate); //wait for x seconds
}
state = SpawnState.Waiting;
Debug.Log("Waiting");
yield break;
}
void SpawnEnemy (Transform _enemy)
{
Debug.Log("Spawning Enemy: " + _enemy.name);
Transform _sp = spawnPoints[Random.Range (0, spawnPoints.Length)];
Instantiate(_enemy, _sp.position, _sp.rotation);
}
}
Answer by enerology · May 25, 2020 at 05:30 PM
You can store the last spawn points in a dictionary then call Dictionary.Contains() to see if that spawn point was already used.
What failed about it. Could you not implement it in code or did the enemies still spawn "on top" of each other? For the prior, I can write it into the code for you and for the latter, it was probably because it's in float form so the units with positions (0,0,0) and (0.01,0,0) would be "on top" of each other with different positions so the dictionary would not contain such. You can fix this by calculating the distance between previous points and checking if the two points distance is less than the size of units.
Here I changed two things 1) added to the top in the fields section
public List<Transform> oldSpawnPoints;
2) added a check in your spawn function
void SpawnEnemy(Transform _enemy)
{
Debug.Log("Spawning Enemy: " + _enemy.name);
int spawnPointIndex = Random.Range(0, spawnPoints.Length);
if (!oldSpawnPoints.Contains(spawnPoints[spawnPointIndex]))
{
Transform _sp = spawnPoints[Random.Range(0, spawnPoints.Length)];
oldSpawnPoints.Add(_sp);
Instantiate(_enemy, _sp.position, _sp.rotation);
}
else
{
Debug.Log("Spawning Position Already Used");
}
}
3) If you need the spawnEnemy to spawn an enemy even after it detected that the spawn position is equal to an old position you could write a for loop and have it try to get a position that does not already exist. If it finds one it can break out of it. like this.
void SpawnEnemy(Transform _enemy)
{
Debug.Log("Spawning Enemy: " + _enemy.name);
int spawnPointIndex = Random.Range(0, spawnPoints.Length);
int numOfTries = 10;
for (int i = 0; i < numOfTries; i++)
{
if (!oldSpawnPoints.Contains(spawnPoints[spawnPointIndex]))
{
Transform _sp = spawnPoints[Random.Range(0, spawnPoints.Length)];
oldSpawnPoints.Add(_sp);
Instantiate(_enemy, _sp.position, _sp.rotation);
Debug.Log("Enemy Successfully Spawned");
break;
}
else
{
Debug.Log("Spawning Position Already Used " + "Try #" + i);
}
}
}
also do you have an idear how i can make it so the _wave.hostage doesn´t always spawn ath the end? but rather at a random point durng the wave
is it possible, that the script keeps objects from spawning if it picks on thats already used ins$$anonymous$$d of just chosing the next spanw point?
I added the 3rd code snippet to replace the second if you wanted this feature. It checks spawning position and tries to spawn a Gameobject if a spawn point was not already used, but if it was, it will try again and again for a total of ten times. If you want I can also add a snippet that on the tenth try, scan through the whole array of points, and if it does not find a not used spawn point, then run an action on this like debug.log( "No more valid spawn points").
Is it possible so it just doesn't chose the same spot twice directly after each other. Other then that they can be used as often as they want