Hello to all. In my game, a bunch of prefabs are randomly placed throughout the map. However, they tend to often spawn on top of each other. I couldn’t find a tutorial explaining a fix for 3D objects, so if someone could give me a hand, I would be thankful. Here is my current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObstaclePlacer : MonoBehaviour
{
public int ObsToPlace = 10;
public GameObject[] Obstacles = new GameObject[0];
GameObject Obstacle;
void Awake()
{
for (int i = 0; i < ObsToPlace; i++)
{
Obstacle = Obstacles[Random.Range(0, Obstacles.Length)];
Vector3 position = new Vector3(Random.Range(-50.0f, 50.0f), 0, Random.Range(-50.0f, 50.0f));
Instantiate(Obstacle, position + Obstacle.transform.position, Quaternion.identity);
}
}
}
Thanks!
I’m on my phone so I can’t write code for you. But I can tell you what to do…
Use Physics.OverlapSphere() to check the spawn position before spawning. This method will collect all colliders in the specified area and return them all in an array. Just go through the array in a loop to look for items that you don’t want to spawn on top of… Then if you find an item you don’t want to spawn on top of, then pick a new random spawn location and repeat the process. (loop)
EDIT:
Try this. You’re going to have to play around with the obstacleCheckRadius variable. It determines how big our check area is.
One warning about my code
My code will not spawn an obstacle after 10 attempts. Therefore even if you want 10 obstacles, you might only get 9 if there’s not enough space to spawn the last one. I did this to prevent an infinite loop from happening, which would crash your Unity and game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObstaclePlacer : MonoBehaviour
{
public int ObsToPlace = 10;
public GameObject[] Obstacles = new GameObject[0];
GameObject Obstacle;
public float obstacleCheckRadius = 3f;
public int maxSpawnAttemptsPerObstacle = 10;
void Awake()
{
for (int i = 0; i < ObsToPlace; i++)
{
Obstacle = Obstacles[Random.Range(0, Obstacles.Length)];
// Create a position variable
Vector3 position = Vector3.zero;
// whether or not we can spawn in this position
bool validPosition = false;
// How many times we've attempted to spawn this obstacle
int spawnAttempts = 0;
// While we don't have a valid position
// and we haven't tried spawning this obstable too many times
while(!validPosition && spawnAttempts < maxSpawnAttemptsPerObstacle)
{
// Increase our spawn attempts
spawnAttempts++;
// Pick a random position
position = new Vector3(Random.Range(-50.0f, 50.0f), 0, Random.Range(-50.0f, 50.0f));
// This position is valid until proven invalid
validPosition = true;
// Collect all colliders within our Obstacle Check Radius
Collider[] colliders = Physics.OverlapSphere(position, obstacleCheckRadius);
// Go through each collider collected
foreach(Collider col in colliders)
{
// If this collider is tagged "Obstacle"
if(col.tag == "Obstacle")
{
// Then this position is not a valid spawn position
validPosition = false;
}
}
}
// If we exited the loop with a valid position
if(validPosition)
{
// Spawn the obstacle here
Instantiate(Obstacle, position + Obstacle.transform.position, Quaternion.identity);
}
}
}
}
As darkforge mentioned, overlapsphere would work out.
It really depends on the size/shape of the object you’re trying to spawn.
On, on your instantiate (psuedo):
Physics.OverlapSphere(or box) at the desired location. Check the collission. If false, you’re good to go. If it fails, loop through it again.
Also, add a FailCount, as there will come a point you just need to fail the operation when too many loops fail, if you don’t, you’ll eventually freeze your game due to a constant running process.
Take a look at Physics.ComputePenetration().
The example script includes the general information necessary to be able to check for nearby objects, then if they are nearby, determine the minimum separation required to keep them apart from each other.