Detect closest object within a collider that has a specific script attached

I am trying to create a custom object grabbing script for Oculus Touch with some extra features that the OVR Grabber and Grabbable scripts dont have (think Syndrome from the Incredibles like control over objects at a distance). After finishing what I thought would be the hard part I got stuck on the simple part of picking up objects with just the hand. More specifically, targeting which one I should actually be grabbing.

What I want to do is detect all the objects within the collider for the hand object (currently called HandTransform which might be a little confusing in retrospect) throw out the ones without the script that indicates that they are grabbable (named Test_Grabbable) find the closest to the transform position of the hand object and use that to run through the rest of my grabbing script.

To that end I tried to use Physics.SphereCast which I quickly discovered was not what I thought it was, tried to work with onTriggerStay/Enter but that got horribly complex very quickly (in part because I didn’t really know what I was doing) and I decided to move on to Physics.OverlapSphere (Since the “hand” is really just a sphere collider) which looks like it might be doing what I want it to but I cant figure out how to do anything with the Collider variable that it returns. I wanted to go though the objects item by item and add them to a new array of “grabbable objects” if they had the Test_Grabbable script attached to them and sort that by distance so I could take the closest but foreach was complaining that there was no public definition for GetEnumerator.

Not sure what to do at this point, google and these forums have been becoming less and less helpful as time goes on. Which is both good and bad I guess. I’m fairly new to Unity and C#, only been at it about 2 weeks and its a pretty step learning curve. I wanted to make sure I wasn’t doing something needlessly complicated or stupidly unconventional. Any help is appreciated; thank you all very much.

The OverlapSphere approach should probably be okay for finding colliders. But I’d suggest two changes, given that you’re developing for VR, and performance is a concern:

  1. Use OverlapSphereNonAlloc. This does the same thing as OverlapSphere, but it does so without generating extra garbage. Instead of returning an array of Colliders, you instead pass in an array which gets reused each time. The array will be filled with colliders, and the return value of OverlapSphereNonAlloc will tell you how many array elements were assigned by the call. The key is that you should declare the array as a private variable of the class, and set it to a reasonable fixed size in the Start method of your class. Here’s an example:

    private Collider[] _overlapping;       
    void Start()
    {
        _overlapping = new Collider[10];  // Or use a number higher than 10 if you want.
    }
    
    void Update()
    {
        // Find other colliders that are within 1.25 times the radius of this object's position.
        var overlapCount = Physics.OverlapSphereNonAlloc(this.transform.position, this._currentRadius * 1.25f, _overlapping);
    
        if (overlapCount > 0)
        {
            for (var overlapIndex = 0; overlapIndex < overlapCount; overlapIndex++)
            {
                var theCollider = _overlapping[overlapIndex];
                // Now do what you want with the collider.
            }
        }
    }
    
  2. Now that you have the colliders, you can access the collider’s gameObject property to get the game object the collider is assigned to. The next performance concern is calling GetComponent() every frame on potentially many objects. That’s an expensive approach. What I personally do in cases where I need to find objects and access their components every frame is to keep a collection of object which I periodically update. There are many ways to do this, but here’s one:

In Start on your script, start a coroutine. In the coroutine, having it find all objects in your scene you might be interested in. (For example, find all objects having a particular script attached.) Put that object in a Dictionary where the key is the gameObject, and the value is the component. Then go through the dictionary and make sure all the objects are still present in the scene. (An object might have been destroyed.) If an object is in your Set/Dictionary, but isn’t in the scene, remove it from your Set/Dictionary. You now have a cache of objects. Having your Coroutine run every N seconds, where N is up to you, but shouldn’t be too frequent or too long. Maybe once per second.

Now, when you are doing your OverlapSphere, and you have the collider’s game object, you can see if it exists in your dictionary. This is much faster than calling GetComponent.

Anyway, neither of these is critical, but it’s worth mentioning.