检查附近物体的碰撞以在 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。
我几乎完成了我在 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。