I am trying to spawn pick-up objects at random places in my game area using an array of spawn points, but I cannot seem to figure out the correct way to check to see an object has already spawned there. I am using an InvokeRepeating() function to instantiate these objects over and over until the player wins or loses. But I don’t want another object to be instantiated where another one already is.
I have tried using OnTriggerEnter(), but since they are both non-kinematic triggers, it does not work. I have tried using CheckSphere(), but since they are instantiated on floating platforms, none end up being instantiated because it senses that the platforms (and probably the empty spawn point objects) intersect. I am going crazy trying to wrack my brain to figure this out.
Please help!
If I understand you correctly, you have a finite set of points where objects could spawn, and you want to make sure that objects may only spawn at one of these points if nothing has spawned there already.
If the spawned objects won’t move, you can keep track of which spawn points have already been used. If the objects can be destroyed, you just need to make sure that when that happens, you mark the corresponding spawn point as unused again.
[SerializedField] Vector3[] _possibleSpawnPoints;
bool[] _usedSpawnPoints; // Corresponds to _possibleSpawnPoints. Eg if _usedSpawnPoints[0] == true, _possibleSpawnPoints[0] is no longer viable
void Awake () {
_usedSpawnPoints = new bool[_possibleSpawnPoints.Length];
}
void SpawnAtRandomSpawnPoint () {
int spawnIndex = Random.Range(0, _possibleSpawnPoints.Length);
int checkedPoints = 0;
while (_usedSpawnPoints[spawnIndex]) { // If a spawn point is occupied
spawnIndex = (spawnIndex + 1) % _possibleSpawnPoints.Length; // Pick the next available spawn point
checkedPoints++;
if (checkedPoints >= _possibleSpawnPoints.Length) {
return; // No spawn points available
}
}
SpawnAtIndex(spawnIndex);
}
void SpawnAtPoint (int index) {
Vector3 spawnLocation = _possibleSpawnPoints[index];
// TODO: Spawn object at spawnLocation
_usedSpawnPoints[index] = true; // Mark spawn point as having been used
}
If you can use a List<T> instead of an array, you could remove points from it as they get used.
If the spawned objects may move, you might want to do something like you were considering, with overlap tests, but make sure the tests only check for the spawned objects, so that your tests don’t include platforms. The easiest way would be with something like Unity - Scripting API: Physics.OverlapSphereNonAlloc, using a LayerMask to exclude the platforms. If the platforms need to be on the same layer, you could still use Physics.OverlapSphereNonAlloc but iterate through the results to exclude the platforms, by using Unity - Scripting API: Component.CompareTag or testing for the presence of a component with Unity - Scripting API: Component.GetComponent using something like results *.GetComponent<Platform>() != null as a test.*