Search code examples
c#unity-game-enginecollision-detection

Checking collisions in near objects for random object spawning in Unity 5


I have almost finished my first game in Unity, which is a simple maze with characters collecting different coins. As it was a hassle to manually put all the different coins in the terrain, I decided to try and make a random generator for the coins.

The script is largely working, but the problem is that it's spawning objects most of the time inside walls. So I tried to add rigid bodies to coins, but this is messing with the coins position as the coins have a script for rotation. I also have the coins collision triggered because they perform a certain action when colliding with the character.

So after some research I saw that I need to check in my generator script for a near object collision and somehow change the spawn position of the coin if it's true. I'm trying to figure out how I can do that. My script is attached to my terrain and it looks like this:

using System.Collections;
using CustomArrayExtensions;
using UnityEngine;

public class ObjectSpawner : MonoBehaviour
{

[SerializeField] public GameObject[] letters;

    GameObject selectedObject;

    private int amount = 0;

    public int limit;

    void Start()
    {
        StartCoroutine(SpawnObjects());
    }


    IEnumerator SpawnObjects()
    {

        selectedObject = letters.GetRandom();

        while (amount < limit)
        {
            Instantiate(selectedObject, new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f)), Quaternion.identity);
            yield return new WaitForSeconds(5.0f);
            amount++;
        }
    }

    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.name == "Fox_Main")
        {
            Debug.Log("Collision Detected");
        }
    }
}

So i tried both answers and they didn't help me.Coins and other objects is still spawning close/inside the walls.My boxes have box collider and rigidbody with all positions/rotations locked(i need it that way so that i can destroy it later without moving it with the character),walls have box collider.So i tried to modify your solutions following Unity Documentation.I failed too.Here is what i have done so far. See here

using System.Collections;
using UnityEngine;

public class RandomCrates : MonoBehaviour
{
  public GameObject[] crates;
  private GameObject selectedCrate;
  public int limit = 0;
  public float x, y, z;
  public float forX_From,forX_To,forZ_From,forZ_To;     
  private int mask = 1 << 7;

  void Start()
  {
      StartCoroutine(SpawnObjects());
  }

  IEnumerator SpawnObjects()
  {
      for (int i = 0; i < crates.Length; i++)
      {
          for (int j = 0; j < limit; j++)
          {
              Vector3 freePos = GetFreePosition();
              Instantiate(crates[i], freePos, Quaternion.identity);
              yield return new WaitForSeconds(0.0f);
          }
      }

  }

  Vector3 GetFreePosition()
  {
      Vector3 position;
      Collider[] collisions = new Collider[1];
      do
      {
          position = new Vector3(Random.Range(forX_From, forX_To), 10.0f, Random.Range(forZ_From, forZ_To));
      } while (Physics.OverlapBoxNonAlloc(position, new Vector3(x, y, z), collisions, Quaternion.identity, mask) > 0);

      return position;
  }

}


Solution

  • Unity provides a simple way to detect collisions in specific position with Physics.OverlapSphere:

    public class ObjectSpawner : MonoBehaviour
    {
        [SerializeField] public GameObject[] letters;
        GameObject selectedObject;
        private int amount = 0;
        public int limit;
        private float radius = 2f; //Radius of object to spawn
    
        void Start()
        {
            StartCoroutine(SpawnObjects());
        }
    
    
        IEnumerator SpawnObjects()
        {
    
            selectedObject = letters[Random.Range(0, letters.Length)];
    
            while (amount < limit)
            {
                Vector3 spawnPos = new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f));
                //Check collisions
                if (DetectCollisions(spawnPos) > 0)
                    continue;
    
                Instantiate(selectedObject, spawnPos, Quaternion.identity);
                yield return new WaitForSeconds(5.0f);
                amount++;
            }
        }
    
        private int DetectCollisions(Vector3 pos) 
        {        
            Collider[] hitColliders = Physics.OverlapSphere(pos, radius);
            return hitColliders.Length;
        }
    
    }
    

    In this way, if there is a collision in spawn position, the coin will not be spawned.