Generate Random Prefabs and check they don't overlap?

I’ve never done something like this before, so i’m giving it a shot, loads might be wrong

using UnityEngine;
using System.Collections;

public class Random_Obstacle_Spawner : MonoBehaviour {

    // Use this for initialization
    public GameObject[] obstacles;
    private float maxX = 90.0f; 
    private float minX = -90.0f;
    private float maxZ = 100.0f;
    private float minZ = -100.0f;
    // size of map

    public int AmountToSpawn;
    void Start ()
    {
        StartCoroutine(spawnObstacles(obstacles));
    }
   
    // Update is called once per frame
    void Update ()
    {
   
    }

    public IEnumerator spawnObstacles(GameObject[] obj)
    {
        Debug.Log("started");

        int num = 0;
        while (num < AmountToSpawn)
        {
            bool checkBound = checkOverlap(obj);
            for (int i = 0; i < obj.Length; i++)
            {
                 obj[i] = (GameObject)Instantiate(obj[i], new Vector3(Random.Range(minX, maxX), 0.5f, Random.Range(minZ, maxZ)), Quaternion.identity); // Instantiate prefabs at random pos
                if (checkBound) // check if colliding
                {
                    Debug.Log("checking");
                    for (int j = 0; j < obj.Length; j++)
                    obj[j].transform.position = new Vector3(Random.Range(minX, maxX), 0.5f, Random.Range(minZ, maxZ));
                }
                AmountToSpawn--; // decrease
            }

        
        }
        yield return null;
    }


    public bool checkOverlap(GameObject[] obj)
    {
        for (int i = 0; i < obj.Length; i++)
        {
            if (obj[i].transform.position == obj[i].transform.position)
            {
                return false;
            }
        }

        return true;
    }
}

the checkOverlap function is not working, is it because i’m comparing itself to itself?

or am i approaching this wrong? any help is appreciated :slight_smile:

you might find working with “bounds” and “overlapbox/sphere” is a cleaner approach. Checking the “position” of the transforms doesn’t take into account the size of the things being compared.

… and yes, comparing an object to itself isn’t going to work.

try [ i] vs [ i+1] and change the middle for parameter to “i < obj.Length-1” so you don’t overshoot the end of the array

Looking into what you said now, another problem I have is the

if (checkBound) // check if colliding
                {
                    for (int j = 0; j < obj.Length; j++)
                    {
                        obj[j].transform.position = new Vector3(Random.Range(minX, maxX), 0.5f, Random.Range(minZ, maxZ));
                       
                    }
                 
                }
    }

function, would this only run once? to check if they’re in the same position, then exit out? would this need to be a continuous function?

What you have provided does not help. It does not convey how you want these prefabs to spawn. I’m assuming in a grid, just not fully filled, but what you wrote does not really seem to do that. It would be far easier to run through all the positions of the grid, and then choose to spawn an object or not, and then what to spawn.

//run through every z position
for(int z = 0; z < gridRows; z++){
    //run through all x positions at the current z position
    for(int x = 0; x < gridColumns; x++){
        //choose whether to spawn an object
        if(Random.range(0f, 1f) > spawnChance){
            //choose object to spawn at current position
            Instantiate (objectList(Random.Range(0, objectList.Lenght - 1)), new Vector3(x, 0, z), Quaternion.identity);
        }
    }
}

Should have been clearer sorry, what i’m going for is there’s a set size map (hence the min Z,Max Z ect…) and it will instantiate random prefabs in this area, if two overlap it will find a new position for the prefab

Do you need the grid to be fully filled in with objects?

Nope, just random obstacles placed you can hide behind, they’re of different shapes though.

Well I’ve given you a solution already, so just try that out first.

I’ve tested using bounds seperately, it works if one object goes into another but not vice versa, it just checks the object next on the list, in my case [0] checks for [1] but [1] doesn’t check for [0]

the code is here

using UnityEngine;
using System.Collections;

public class CheckBounds : MonoBehaviour {

    // Use this for initialization

    public Bounds[] bounds;
    public GameObject[] objs;
    void Start ()
    {
        bounds = new Bounds[objs.Length];
        for (int i = 0; i < bounds.Length; i++)
        {
            bounds[i] = objs[i].GetComponent<BoxCollider>().bounds;
        }

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

        for (int i = 0; i < objs.Length - 1; i++)
        {
            if (objs[i].GetComponent<BoxCollider>().bounds.Intersects(bounds[i + 1]))
            {
                Debug.Log("pls");
            }
        }
    }
}

Is there a way i can somehow check if it intersects with any object in the array, apart from itself?

If you are insistent on this method, that’s because you need to have a target to check against everything else. Without a target the script isn’t really doing anything useful.

bool HasIntersectionWith(GameObject target){
    for (int j = 0; j < objs.Lenght; j++){
        if(target.GetComponent<BoxCollider>().bounds.Intersects(objs[j].GetComponent<BoxCollider>().bounds)){
            return true;
        }
    }
    return false;
}

I was thinking more “use bounds to work out an appropriate “size” box, overlapbox test that box which will be a test against all colliders in the scene, if nothing comes back all good, if something comes back, there’s something there” :slight_smile:

I’ve been searching google for other methods, or even ways to do it and most links back to the same thing…

http://answers.unity3d.com/questions/614293/objects-not-deleting-themselves-when-touching-othe.html

EDIT: I don’t want objects to delete themselves, just searching for the same type of concept

Can anyone link me possible methods? I keep running into the same issue, even with adding a target. It doesn’t check the collision on instantiated prefabs…

Got it working by storing the instantiated objects in a temp, and the bounds in a temp

Then checked the Target with the bounds

using UnityEngine;
using System.Collections;

public class Spawner : MonoBehaviour {

    public GameObject[] obstacles;
    private float maxX = 150.0f;
    private float minX = -150.0f;
    private float maxZ = 200.0f;
    private float minZ = -200.0f;
    public Bounds[] bound;
    public int AmountToSpawn;
    public GameObject Target;
    [SerializeField] private GameObject[] tempObs;
    // Use this for initialization
    void Start ()
    {
        bound = new Bounds[AmountToSpawn];
        tempObs = new GameObject[AmountToSpawn];
        StartCoroutine(spawn(obstacles));

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

    }


    public IEnumerator spawn(GameObject[] objs)
    {
        int num = 0;
        while (num < AmountToSpawn)
        {
            for (int i = 0; i < tempObs.Length; i++)
            {
                GameObject targ = Target;
                targ.transform.position = new Vector3(Random.Range(minX, maxX), 0.5f, Random.Range(minZ, maxZ));
             
                if (hasCollisions(targ))
                {
                    targ.transform.position = new Vector3(Random.Range(minX, maxX), 0.5f, Random.Range(minZ, maxZ));
                }
                else
                {
                    tempObs[i] = (GameObject)Instantiate(objs[Random.Range(0, 2)], targ.transform.position, Quaternion.identity);
                    bound[i] = tempObs[i].GetComponent<BoxCollider>().bounds;


                }

                num++;
            }
         
            Debug.Log(num);
        }

        yield return null;


    }

    bool hasCollisions(GameObject target)
    {
        for (int j = 0; j < tempObs.Length; j++)
        {
            if (target.GetComponent<BoxCollider>().bounds.Intersects(bound[j]))
            {
                return true;
            }

        }
        return false;
    }
}

if it doesn’t have enough room, it stops spawning :slight_smile: