简体   繁体   English

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

[英]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.我几乎完成了我在 Unity 中的第一款游戏,这是一个简单的迷宫,角色们收集不同的硬币。 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.所以我尝试为硬币添加刚体,但这与硬币 position 相混淆,因为硬币有一个旋转脚本。 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.因此,经过一些研究,我发现我需要检查我的生成器脚本是否存在近 object 碰撞,并以某种方式更改硬币的生成 position 如果它是真的。 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.所以我尝试了这两个答案,但它们都没有帮助我。硬币和其他物体仍在靠近/在墙壁内产生。我的盒子有盒子对撞机和刚体,所有位置/旋转都被锁定(我需要这样才能摧毁稍后它不随角色移动),墙壁有盒子对撞机。所以我尝试按照 Unity 文档修改你的解决方案。我也失败了。这是我到目前为止所做的。 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 provides a simple way to detect collisions in specific position with Physics.OverlapSphere : Unity 提供了一种简单的方法来检测特定 position 与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.这样,如果在 spawn position 中发生碰撞,则不会生成硬币。

There are different ways of approaching this problem and given more information one could come up with a smarter approach.有不同的方法可以解决这个问题,如果提供更多信息,人们可能会想出更聪明的方法。 However, to provide you with a simple solution to your problem: You could just pick random positions until you find a "free spot".但是,为您提供解决问题的简单方法:您可以选择随机位置,直到找到“空闲位置”。 Assuming your coins to have a size of 1, you could do something like:假设您的硬币大小为 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;
}

Please note that Physics.OverlapSphereNonAlloc() can also accept a LayerMask for filtering collisions based on layers.请注意Physics.OverlapSphereNonAlloc()也可以接受一个LayerMask来过滤基于层的碰撞。 You might want to look into this, to prevent detecting collision with your terrain, which may well keep the do-while loop from exiting and freeze Unity.您可能需要对此进行研究,以防止检测到与地形的碰撞,这很可能会阻止 do-while 循环退出并冻结 Unity。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM