Hi so i would like to create a system that allows random resources to spawn on my map without it spawning inside the buildings (white boxes) But don’t know how to do so pls help
Hi,
Try to split your problem to pieces and then think how to solve each of them individually. What do you need to know to have a location that is not a building? The answer is of course detect the buildings and exclude those from potential positions.
So, what could you do in practice? You could raycast at random positions down from the sky and if the ray doesn’t hit a building, then instantiate an object to that location.
I’m sure with some googling you can find many examples how to actually implement this. You need to figure out how to do that raycasting and then how to instantiate your prefab from an array.
Yeah that actually sounds like a good idea thanks ^^
Just ask if you get stuck. And I think that’s nothing to be concerned about if you need to test 3-4 times before you hit a free spot. Or even more times. Of course if you need to spawn 20-30 things in one second all the time, then it’s better to think about more optimized solutions like somehow caching the locations that are valid. This could be done by creating some sort of array of valid locations, for example. Or use some more sophisticated methods.
Yeah i’m going to use it once every ingame day for like 50 objects max so i think it’s not going to cause issues
Or you could use the building Collider to check if a spawned object is inside a building:
using UnityEngine;
using System.Collections.Generic;
public class MyScript : MonoBehaviour
{
public List<Collider> buildings = new List<Collider>();
public List<GameObject> spawnObjects = new List<GameObject>();
public Collider map;
float mapWidth;
float mapLength;
int numberOfObjectsToSpawn;
int minNumberToSpawn = 10;
int maxNumberToSpawn = 50;
GameObject go;
Transform tr;
Collider col;
List<Collider> spawnedObjects = new List<Collider>();
private void Start()
{
mapWidth = map.bounds.extents.x;
mapLength = map.bounds.extents.z;
numberOfObjectsToSpawn = Random.Range(minNumberToSpawn, maxNumberToSpawn + 1);
for (int i = 0; i < numberOfObjectsToSpawn; i++)
{
go = Instantiate(spawnObjects[Random.Range(0, spawnObjects.Count)]);
tr = go.transform;
col = go.GetComponent<Collider>();
do
{
tr.position = new Vector3(Random.Range(-mapWidth, mapWidth), map.transform.position.y + col.bounds.extents.y, Random.Range(-mapLength, mapLength));
}
while (IsInBuildingOrInSpawnedObject(col));
spawnedObjects.Add(col);
}
}
private bool IsInBuildingOrInSpawnedObject(Collider c)
{
bool b = false;
for (int i = 0; i < buildings.Count; i ++)
{
b = buildings[i].bounds.Contains(c.ClosestPoint(buildings[i].transform.position));
if (b)
{
return b;
}
}
for (int j = 0; j < spawnedObjects.Count; j++)
{
if (spawnedObjects[j] != c)
{
b = spawnedObjects[j].bounds.Contains(c.ClosestPoint(spawnedObjects[j].transform.position));
if (b)
{
return b;
}
}
}
return b;
}
}
Hey quick question how do i go about the raycasts? Cause i have no clue how to get them to be able to cast everywhere on the map like do i create some object that gives it base or what?
You can just pick a random position within the dimensions of your ground, for example. i.e. get the XZ dimensions first, then cast a ray down from some arbitrary height.
Use something like this to get the dimensions of your ground, I wrote a quick example:
Bounds groundsBounds;
// Object you wish to get bounds of
public GameObject target;
In Start, cache the bounds:
groundsBounds = target.gameObject.GetComponent<Collider>().bounds;
Then, somewhere, where you intend to do the raycasting:
// Get bounds min max on XZ-ground plane
float minX = groundsBounds.min.x;
float maxX = groundsBounds.max.x;
float minZ = groundsBounds.min.z;
float maxZ = groundsBounds.max.z;
// Randomize X and Z values within bounds
float randomX = Random.Range(minX, maxX);
float randomZ = Random.Range(minZ, maxZ);
Now use these values to generate some raycast origin point:
float y = 10f; // How high we start from, 10 meters in this case
Vector3 testPosition = new Vector3(randomX, y, randomZ);
Now you can raycast from that point down…
// Perform a raycast
RaycastHit hit;
if (Physics.Raycast(testPosition, Vector3.down, out hit, Mathf.Infinity))
{
// If we hit object tagged as "Ground"
if (hit.transform.gameObject.tag == "Ground")
{
Debug.DrawRay(testPosition, Vector3.down * hit.distance, Color.green, 1f);
Debug.Log("Hit Ground");
}
// If not hit something else withing bounds.
else
{
Debug.DrawRay(testPosition, Vector3.down * hit.distance, Color.red, 1f);
Debug.Log("Hit something else");
}
}
Then you would naturally need to store the location you hit that was valid. You can do that by saving the hit.point, i.e:
// Spawn position would be Vector3 type
spawnPosition = hit.point;
Godamn… Works like a miracle many thanks my guy!
Uh one thing and i think its done but when i instantiate an object it spawns it under the map? and not on top of it

You must have some basic thing wrong - collider below the ground, or some hierarchy in your objects you instantiate. (i.e. like having empty root for an object and then the visible part is offset.)
Raycast will very likely hit the correct spot on any collider. And instantiated things go where they are supposed to. So check your assets first before anything else.
EDIT: just drag your object(s) you instantiate to the Editor, check their transform and move them to 0,0,0 and then see where that visible part (aka your object) is. It might not be where you expect if you’ve done something wrong with the asset when exporting it or in Unity.
Yep it wasn’t on 0,0,0 my mistake thanks again it works properly!
Click that like button if it was helpful. Not many do that! ![]()
