将多个物体的碰撞器作为一个碰撞器使用
Use the collider of multiple objects as one collider
在我的 fps 级别 (Unity) 中,目标生成在随机位置。我想确保目标不会在物体后面或物体内部生成。
为了确保它们不会在物体后面生成,我制作了一个从玩家到目标的 raycast
。如果它被阻挡,我会重新计算重生点。这工作正常,但是,由于目标是球体,所以当目标 50% 位于对象(例如地板)内部时,光线投射不会被阻挡。显然,我不想那样。
为了确定目标是否在另一个对象的范围内,我尝试使用 OnCollisionEnter
和 OnCollisionExit
。虽然这在简单地将目标移动到另一个对象内时有效,但当一个脚本的更新周期正在重新计算生成位置而目标的更新周期正在跟踪碰撞时,它似乎不可靠。
所以我寻找了一种不同的方法。这是我想出的(来自 Unity 文档):
m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
}
游戏对象世界是我放置游戏世界所有对象的父级。
问题是他只考虑了第一个物体的collider。我基本上想用一个大对撞机,它由所有关卡对象组成。
这可能吗?或者有人知道我如何实现这一目标的不同方法吗?
您应该使用 GetComponentsInChildren
方法而不是 GetComponentInChildren
,这样您就可以从中获得一个 collider
数组,您可以在该数组上执行 foreach
检查 bounds
是否相交。
即:
m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
if (objCollider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
但是,这种做事方式对于 CPU 来说非常繁重,因为 GetComponent
方法真的很慢,所以它们的使用应该限制在 Awake
和 [=21] 中=] 可能的方法。
解决该问题的另一种方法是在开始时创建一个 List<Collider>
,并向其添加 World 游戏对象的起始子项。如果另一个被实例化,就 Add
它到你的列表,如果它被销毁,就 Remove
它。
然后,在实例化之前,您可以通过在 List
中使用 foreach
循环来检查 bounds
,检查会快很多。
==================================
编辑:
好的,这就是交易。首先,将这些行添加到您的 World
游戏对象脚本(我猜您调用了 class World
):
using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type
public class World : MonoBehaviour {
//The list which will hold references to the children game objects colliders
public List<Collider> childrenColliders;
private void Start() {
//Code used to populate the list at start
childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
}
现在,因为在生成新对象的脚本中已经有一个 world
变量,它包含对 World
class:
的引用
foreach(Collider coll in world.childrenColliders) {
if (coll.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
当然,正如我之前所说,请记住将新生成的游戏对象的对撞机添加到列表中:
void AddNewGameObject() {
// spawnPoint is the transform.position Vector3 you'll use for the new game object
var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}
差不多就是这些了。 ;)
在我的 fps 级别 (Unity) 中,目标生成在随机位置。我想确保目标不会在物体后面或物体内部生成。
为了确保它们不会在物体后面生成,我制作了一个从玩家到目标的 raycast
。如果它被阻挡,我会重新计算重生点。这工作正常,但是,由于目标是球体,所以当目标 50% 位于对象(例如地板)内部时,光线投射不会被阻挡。显然,我不想那样。
为了确定目标是否在另一个对象的范围内,我尝试使用 OnCollisionEnter
和 OnCollisionExit
。虽然这在简单地将目标移动到另一个对象内时有效,但当一个脚本的更新周期正在重新计算生成位置而目标的更新周期正在跟踪碰撞时,它似乎不可靠。
所以我寻找了一种不同的方法。这是我想出的(来自 Unity 文档):
m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
}
游戏对象世界是我放置游戏世界所有对象的父级。
问题是他只考虑了第一个物体的collider。我基本上想用一个大对撞机,它由所有关卡对象组成。
这可能吗?或者有人知道我如何实现这一目标的不同方法吗?
您应该使用 GetComponentsInChildren
方法而不是 GetComponentInChildren
,这样您就可以从中获得一个 collider
数组,您可以在该数组上执行 foreach
检查 bounds
是否相交。
即:
m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
if (objCollider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
但是,这种做事方式对于 CPU 来说非常繁重,因为 GetComponent
方法真的很慢,所以它们的使用应该限制在 Awake
和 [=21] 中=] 可能的方法。
解决该问题的另一种方法是在开始时创建一个 List<Collider>
,并向其添加 World 游戏对象的起始子项。如果另一个被实例化,就 Add
它到你的列表,如果它被销毁,就 Remove
它。
然后,在实例化之前,您可以通过在 List
中使用 foreach
循环来检查 bounds
,检查会快很多。
==================================
编辑:
好的,这就是交易。首先,将这些行添加到您的 World
游戏对象脚本(我猜您调用了 class World
):
using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type
public class World : MonoBehaviour {
//The list which will hold references to the children game objects colliders
public List<Collider> childrenColliders;
private void Start() {
//Code used to populate the list at start
childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
}
现在,因为在生成新对象的脚本中已经有一个 world
变量,它包含对 World
class:
foreach(Collider coll in world.childrenColliders) {
if (coll.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
当然,正如我之前所说,请记住将新生成的游戏对象的对撞机添加到列表中:
void AddNewGameObject() {
// spawnPoint is the transform.position Vector3 you'll use for the new game object
var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}
差不多就是这些了。 ;)