检查附近物体的碰撞以在 Unity 5 中产生随机物体

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

我几乎完成了我在 Unity 中的第一个游戏,这是一个简单的迷宫,角色收集不同的硬币。由于手动将所有不同的硬币放入地形很麻烦,我决定尝试为硬币制作一个随机生成器。

该脚本基本上可以正常工作,但问题是它大部分时间都在墙内生成对象。所以我试着给硬币添加刚体,但这会弄乱硬币的位置,因为硬币有一个旋转脚本。我还触发了硬币碰撞,因为它们在与角色碰撞时会执行特定动作。

因此,经过一些研究后,我发现我需要检查我的生成器脚本是否存在近距离物体碰撞,如果是,则以某种方式更改硬币的生成位置。我想弄清楚我该怎么做。我的脚本附加到我的地形,它看起来像这样:

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");
        }
    }
}

所以我尝试了两个答案,但都没有帮助 me.Coins 并且其他对象仍在生成 close/inside walls.My 盒子有盒子碰撞器和刚体 positions/rotations 锁定(我需要这样,这样我以后就可以销毁它而不用移动它与角色),墙壁有盒子 collider.So 我试图在 Unity 之后修改你的解决方案 Documentation.I 失败 too.Here是我到目前为止所做的。 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;
  }

}

Unity 提供了一种简单的方法来检测特定位置的碰撞 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;
    }

}

这样,如果刷出位置发生碰撞,硬币将不会刷出。

有多种方法可以解决这个问题,如果提供更多信息,人们可能会想出一种更明智的方法。但是,为您提供一个简单的解决方案来解决您的问题:您可以随机选择位置,直到找到“空闲位置”。 假设你的硬币大小为 1,你可以这样做:

IEnumerator SpawnObjects()
{
    selectedObject = letters.GetRandom();

    while(amount < limit)
    {
        Vector3 freePos = GetFreePosition();
        Instantiate(selectedObject, freePos), Quaternion.identity);
        yield return new WaitForSeconds(5.0f);
        amount++;
    }
}

Vector3 GetFreePosition()
{
    Vector3 position;
    Collider[] collisions = new Collider[1];
    do
    {
        position = new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f));
    }
    while(Physics.OverlapSphereNonAlloc(position, 1f, collisions) > 0);

    return position;
}

请注意 Physics.OverlapSphereNonAlloc() 也可以接受 LayerMask 以基于图层过滤冲突。您可能想研究一下,以防止检测到与地形的碰撞,这很可能会阻止 do-while 循环退出并冻结 Unity。