首页 > 解决方案 > 如何在场景中找到彼此最近的物体

问题描述

在现场,我有多个四处游荡的物体。

我需要创建一个系统来检查哪些对象彼此靠近并执行一些逻辑。

例如:

我在场景中有 40 个对象。他们都四处游荡。系统检测到 object4 和 object30 彼此靠近。做一些逻辑(在这两个对象之间随机选择并销毁)。

有什么有效的方法吗?

标签: c#unity3d

解决方案


为了对对象何时彼此靠近进行逻辑处理,您首先必须计算到您感兴趣的每个对象的距离。您可以在脚本中的每个对象本身中执行此操作,也可以使用一个脚本来跟踪所有对象他们。

选项 1:一个脚本跟踪所有对象

第一种方式显示了单个脚本如何跟踪所有对象并检查它们是否低于某个阈值。在示例脚本中,对象将通过检查器填充,但您也可以使用标签系统和GameObject.FindGameObjectsWithTag

public class Tracker : MonoBehaviour
{
    public GameObject[] trackingObjects;
    public float threshold = 1f;

    void Update()
    {
        for(int i = 0; i < trackingObjects.Length; i++){
            for(int j = i+1; j < trackingObjects.Length; j++){
                Transform objOne = trackingObjects[i].transform;
                Transform objTwo = trackingObjects[j].transform;
                float distance = Vector3.Distance(objOne.position, objTwo.position);
                if (distance < threshold){
                    Debug.Log(objOne.name + " near " + objTwo.name);
                }
            }
        }
    }
}

选项 2:对撞机

这个选项稍微复杂一些,因为每个对象都需要一个刚体和一个碰撞器,并将 isTrigger 设置为 true。(然后,此触发器的大小将等于您要检查的范围)。使用以下解决方案,两个对象在彼此靠近时都会触发此功能,这与单个脚本跟踪方法不同。

public class IsNear : MonoBehaviour
{
    void OnTriggerEnter(Collider obj){
        Debug.Log(obj.name + "is near");
    }
}

选项 3:个人跟踪(无对撞机)

这与第一个选项相同,但每个对象都有一个单独的脚本,不需要碰撞器或附加刚体。它还允许为每个对象配置阈值,而不是作为单个值(与选项 1 一样)

public class IsNear : MonoBehaviour
{
    public GameObject[] otherObjects;
    public float threshold; 

    void Update(){
        for(int i = 0; i < otherObjects.Length; i++){
            Transform otherObj = otherObjects[i].transform;
            float distance = Vector3.Distance(transform.position, otherObj.position);
            if (distance < threshold){
                Debug.Log(gameObject.name + " near " + otherObj.name);
            }
        }
    }
}

值得注意的是,由于这些是距离检查,它们可以通过不执行 Vector3.Distance 所做的平方根运算来进行更多优化,但由于您只有 40 个对象,因此可能不会优化。(除非您正在跟踪可能成百上千的对象)

优化的阈值检查:

public GameObject[] trackingObjects;
public float squaredThreshold = 1f;

void Update()
{
    for(int i = 0; i < trackingObjects.Length; i++){
        for(int j = i+1; j < trackingObjects.Length; j++){
            Transform objOne = trackingObjects[i].transform;
            Transform objTwo = trackingObjects[j].transform;
            Vector3 toOtherObject = objOne.transform.position - objTwo.transform.position;
            
            if (toOtherObject.sqrMagnitude < squaredThreshold){
                Debug.Log(objOne.name + " near " + objTwo.name);
            }
        }
    }
}

推荐阅读