How to randomly instantiate cubes that don't overlap?

I’m trying to randomly instantiate cubes on the x and y axis but they keep overlapping. Can someone point me in the right direction to prevent them from overlapping when instantiated?

2 Likes

You could have an array of positions where you’ve previously instantiated cubes, and check the random position for a new cube doesn’t conflict with previous positions in the array - you could define a minimum gap between cubes.

I had been thinking about this lately because I am going to need it in an upcoming project. What I am going to attempt to do is have 2 prefabs. First one is my cube and the second one is an empty gameobject with a script that uses SphereCast to see if there are any objects its touching. So from there I would randomly figure out my Vector3, Call the SphereCast prefab. If it finds something then destroy the SphereCast object and randomize the location again. Else if it didn’t find an object then destroy the sphereCast object and spawn a cube in its place.

Perhaps you can just cast a ray from the new position up and test it.

One way to do this without sphere checks or ray casts it to create a random spatial partition tree then spawn a cube randomly within each leaf node.

Rough algorithm outline is:

  • Start with a min/max bounding box in 2D.
  • Split somewhere randomly on the x axis so you get two bounding boxes.
  • Split each of these new bounding boxes randomly on the y axis so you now have four bounding boxes.
  • Continue the process of splitting the boxes along each axis until you have enough boxes.
  • Spawn a single cube prefab randomly within each box

The tricky part of this is selecting a good point to perform the splitting of a bounding box.
You need to make sure that each new bounding box you create is large enough to hold however many leaf boxes it will eventually contain.
This means that for each level of the tree you need to know an inset from the min and max bound where it is safe to split and chose a random point between the two inset bounds.

1 Like

I’m still testing things out, but for now, I haven’t figured it out. Having cubes of varying width and height make it hard to check for overlap. As of now, I can only manage to prevent cubes from spawning partially outside of a grid.

Ok well maybe the same method that I posted above will work but we will changing it a little. Rather than using Shpere cast spawn the object in a random space but turn off the rederer. If its collider hits then move it to another random space until if finds one it fits in.

Gibbonator, that sounds incredibly complicated and possibly outside of my skill level. I’m thinking of trying to place various spawn points and create different sized grids, taking the sizes into account and instantiating 1 cube in each spawn point’s grid.

I think the better method is to use Spherecast as ardizzle sayd. But you can use it without instantiating any gameObject: just call the Physics.SphereCast on the position to test for and with the size you want (varying it as needed).

I’m trying to do the same thing in the game I’m working on right now, and I’m having the same problem. I’m not sure what RayDawg is using in the code, but I’m using Random.Range to spawn the objects within the play area, but they keep overlapping. I’m new to scripting and Unity3D, so some of these answers are foreign to me, such as the stuff involving SphereCast. Could anyone give an example of a code for this because I’m sure that would help us a lot! Thanks.

– Chris

Hello, this script just came to my mind as I was reading your posts. I just tested it and it runs just fine :slight_smile:

public static class PhysicsEx
{
    public static bool CheckBounds(Vector3 position, Vector3 boundsSize, int layerMask)
    {
        Bounds boxBounds = new Bounds(position, boundsSize);

        float sqrHalfBoxSize = boxBounds.extents.sqrMagnitude;
        float overlapingSphereRadius = Mathf.Sqrt(sqrHalfBoxSize + sqrHalfBoxSize);

        /* Hoping I have the previous calculation right, move on to finding the nearby colliders */
        Collider[] hitColliders = Physics.OverlapSphere(position, overlapingSphereRadius, layerMask);
        foreach (Collider otherCollider in hitColliders)
        {
            //now we ask each of thoose gentle colliders if they sens something is within their bounds
            if (otherCollider.bounds.Intersects(boxBounds))
                return (false);
        }
        return (true);
    }

    public static bool CheckBounds2D(Vector2 position, Vector2 boundsSize, int layerMask)
    {
        Bounds boxBounds = new Bounds(position, boundsSize);

        float sqrHalfBoxSize = boxBounds.extents.sqrMagnitude;
        float overlapingCircleRadius = Mathf.Sqrt(sqrHalfBoxSize + sqrHalfBoxSize);

        /* Hoping I have the previous calculation right, move on to finding the nearby colliders */
        Collider2D[] hitColliders = Physics2D.OverlapCircleAll(position, overlapingCircleRadius, layerMask);
        foreach (Collider2D otherCollider in hitColliders)
        {
            //now we ask each of thoose gentle colliders if they sens something is within their bounds
            if (otherCollider.bounds.Intersects(boxBounds))
                return (false);
        }
        return (true);
    }
}

edit: added a nice static wrapper arround it, too bad static extensions aren’t possible or it could have actually extended the Physics class !
edit2: Changed the parameters to better suit the use of this, also added a 2D version (untested)

1 Like

Thank you for the example, but would SphereCast work with 2D, or would I have to use something like a circle? My game is 2D, so I don’t need any Vector3s or spheres. Also, would Bounds work with 2D?

– Chris

You’re welcome and no problem for 2D, just replace the 3D stuff with 2D one and you’ll be fine.

Physics2D.OverlapCircle instead of Physics.OverlapSphere, and yes bounds work in 2D as well. Simply check out the Collider2D documentation and you’ll see the bounds property is still available and using the same class.

Thanks! I’ll give it a try!

– Chris

Sorry to ask this of you, but could you write the code in UnityScript because I know very little about C#. I tried to translate this code over, but it’s rather difficult since I’m still in the process of learning UnityScript. Half of my script is in UnityScript, so I can’t have the other half be C#. If you don’t know much about UnityScript, maybe you could translate my half of the code into C#? I’d really appreciate this!! :smile:

– Chris

hm I’ll try but usually it makes me sick…

function CheckBox(var position : Vector2, var boxSize : float, var layerMask : int)
    {
        /* First some middle grade trigonometry to get the radius of the overlapping sphere */
        var halfBoxSize : float = boxSize / 2;
        var sqrHalfBoxSize : float = halfBoxSize * halfBoxSize;
        var overlapingCircleRadius : float= Mathf.Sqrt(sqrHalfBoxSize + sqrHalfBoxSize);

        var boxBounds : Bounds = Bounds(position, Vector3(boxSize, boxSize, 0));

        /* Hoping I have the previous calculation right, move on to finding the nearby colliders */
        var hitColliders : Collider[] = Physics2D.OverlapCircle(position, overlapingCircleRadius, layerMask);
        for(var otherCollider : Collider in hitColliders)
        {
            //now we ask each of thoose gentle colliders if they sens something is within their bounds
            if (otherCollider.bounds.Intersects(boxBounds))
                return (false);
        }
        return (true);
    }

I’m really not sure it’ll work out of the box but it should help you get started at least, and I really don’t want to create a JS file in my unity project, he’s still a virgin so I hope you understand…

Now if you excuse me, I have to p*ke. :smile:

6 Likes

How about this: Unity - Scripting API: Physics.CheckSphere ?

1 Like

It’s pretty much the same idea except it doesn’t take the objects shapes into account.

It may be totally fine, depends on what they want to acheive…

ps: I even named the method “CheckBox” to give the feeling of equivalence with this very method your pointing out.

1 Like

I don’t mean to dis your method of doing this, _met44, but I found my own very simple way of doing it! Here’s the code:

function Start ()
{
    // Randomly spawn the object within the specified range.
    var newPositionX : float = Random.Range (-5.5, 75.5)
    transform.position.x = newPositionX;
    var newPositionY : float = Random.Range (-2.5, 4.5);
    transform.position.y = newPositionY;
}

function OnCollisionEnter2D (col : Collision2D)
{
    Debug.Log ("Ouch!");
   
    // If collision with objects tagged "Obstacle," repeat Start function.
    if (col.gameObject.CompareTag ("Obstacle"))
    {
        Start ();
    }
}

This was NOT easy for me to accomplish, so I’m very proud of it! The problem I had with your code, _met44, was that I’m new to scripting, so it looked foreign to me! Plus, my version is shorter. Obviously, the Debug.Log statement could be replaced with a print statement or removed entirely. I only added that in there to tell me how many times the object collided, which tells me how many times the Start function was repeated because I don’t want it to repeat too many times. I hope this helps everyone! Again, thanks for the help, everyone!

– Chris

2 Likes

yes obviously you can do that, someone pointed it out before I believe. I thought you asked for a way to do it before instanciating the cube…

It’s great if this fits your needs, what you need most when starting is fun results that motivate you to keep going forward !

I wish you best luck :slight_smile:

1 Like