【问题标题】:Use the collider of multiple objects as one collider使用多个物体的碰撞器作为一个碰撞器
【发布时间】:2018-07-07 08:32:36
【问题描述】:

在我的 fps 级别 (Unity) 中,目标在随机位置生成。我想确保目标不会在对象后面或对象内部生成。

为了确保它们不会在物体后面生成,我制作了一个raycast 从玩家到目标。如果它被阻挡,我会重新计算生成点。这很好用,但是,由于目标是球体,因此当目标位于对象(例如地板)内的 50% 时,光线投射不会被阻挡。很明显,我不想这样。

为了确定目标是否在另一个对象的范围内,我尝试使用OnCollisionEnterOnCollisionExit。虽然这在简单地将目标移动到另一个对象内时有效,但当一个脚本的更新周期正在重新计算生成位置而目标的更新周期正在跟踪碰撞时,它似乎是不可靠的。

所以我寻找了一种不同的方法。这是我想出的(来自 Unity 文档):

m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
    Debug.Log("Bounds intersecting");
}

游戏对象世界是我放置游戏世界所有对象的父对象。

问题是他只考虑了第一个对象的对撞机。我基本上想用一个大对撞机,它是由所有关卡对象组成的。

这可能吗?或者有人知道我如何实现这一目标的不同方法吗?

【问题讨论】:

    标签: unity3d collider


    【解决方案1】:

    您应该使用GetComponentsInChildren 方法而不是GetComponentInChildren,这样您就可以从中获取colliders 的数组,您可以在该数组上执行foreach 来检查bounds 是否相交。

    IE:

    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 方法真的很慢,所以如果可能的话,它们的使用应该限制在 AwakeStart 方法中。

    解决这个问题的另一种方法是在开始时创建一个List&lt;Collider&gt;,并将您的 World 游戏对象的起始子对象添加到它。如果另一个实例被实例化,只需 Add 将其添加到您的列表中,如果它已被销毁,则只需 Remove 它。

    然后,就在实例化之前,您可以通过在List 中循环使用foreach 来检查bounds,检查会快很多。

    ===================================

    编辑:

    好的,这就是交易。首先,将这些行添加到您的 World 游戏对象脚本中(我猜您将类称为 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 类的引用:

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

    差不多就是这样。 ;)

    【讨论】:

    • 感谢您的评论。好的,所以使用 GetComponent 不是一种选择。我了解您列出建议的基础知识,但由于我对 C Sharp 和 Unity 很陌生,所以我真的不知道该怎么做。有没有机会再详细说明一下?
    • 编辑了答案以提供更多见解和实用的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    相关资源
    最近更新 更多