How to find closest objects to each other in scene

On scene i have multiple objects that wandering around.

I need to create a system which will check which objects are near to each other and do some logic.

For example:

I have 40 objects in the scene. They all wandering around. System detects that object4 and object30 are close to each other. Do some logic (choose randomly between this two objects and destroy).

Is there any effiecent ways to do?

Upvotes: 0

Views: 762

Answers (1)

Jason Attwood
Jason Attwood

Reputation: 81

In order to do logic on when objects are near to each other you would first have to calculate the distance to every object that you are interested in. You could either do this in each object itself in a script or have one script that tracks all of them.

Option 1: One script tracking all objects

This first way shows how a single script can track all the objects and check if they fall below a certain threshold. In the example script the objects would be populated via the inspector but you could also use the tag system and 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);
                }
            }
        }
    }
}

Option 2: Colliders

This option is slightly more involved as each object needs both a rigidbody and a collider with isTrigger set as true. (The size of this trigger would then be equivalent to the range you want to check for). With the below solution both objects would fire this function when they each got near to each other which is different from the single script tracking method.

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

Option 3: Individual Tracking (without colliders)

This is the same as the first option but each object would have an individual script and not require colliders or a rigidbody attached. It also allows for the threshold to be configured per object rather than as a single value (as with option 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);
            }
        }
    }
}

Its worth noting that as these are distance checks they can be optimised more by not performing the square root operation that Vector3.Distance does but as you only have 40 Objects its likely not optimising. (Unless you were tracking possibly hundreds or thousands of objects)

Optimised Threshold checking:

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

Upvotes: 1

Related Questions