Raycasting, multiple hits within the same priority layer bug and my solution

First of all I would like to say that the new CameraRaycaster class is working great, it has however introduced a small bug where if you have more than 1 hit within the same priority layer, it will not check for the closest hit but just return the first hit it finds within the priority layer that it is currently checking.
In my game this made it impossible to click on and walk over certain bridges, as it found the hit on the terrain first and did never even check the hit on the bridges which were also in the Walkable layer.

In case anyone else is having the same problem I do provide my solution here below.

RaycastHit? FindTopPriorityHit (RaycastHit[] raycastHits)
{
    // Form list of layer numbers hit
    List<int> layersOfHitColliders = new List<int> ();
    foreach (RaycastHit hit in raycastHits)
    {
        layersOfHitColliders.Add (hit.collider.gameObject.layer);
    }

    // Step through layers in order of priority looking for a gameobject with that layer
    foreach (int layer in layerPriorities)
    {
        // A variable for holding the indext to the currently closest most highpriority hit
        int topPriorityHitIndex = -1;

        // Loop through all hits, need to check all hits for each priority layer in case
        // there is more than one hit within the same priority layer
        for (int i = 0; i < raycastHits.Length; i++)
        {
            if (raycastHits[i].collider.gameObject.layer == layer)
            {
                // Check if any previous hits with the same priority has already been found
                if(topPriorityHitIndex >= 0)
                {
                    // Check if this hit is closer
                    if(raycastHits[i].distance < raycastHits[topPriorityHitIndex].distance)
                    {
                        topPriorityHitIndex = i;
                    }
                }
                else
                {
                    topPriorityHitIndex = i;
                }
            }
        }

        // Check if any hits were found for this priority layer
        if(topPriorityHitIndex >= 0)
        {
            return raycastHits[topPriorityHitIndex];// Stop looking
        }
    }
    return null; // because cannot use GameObject? nullable
}
2 Likes

Thanks for sharing :slight_smile:

Interesting approach, I also ran in to this problem, but my solution is a bit different and a lot more simple

RaycastHit[] raycastHits = Physics.RaycastAll(ray, maxRaycastDepth).OrderBy(h => h.distance).ToArray();

Note the added .OrderBy().ToArray()

This orders the list by distance in advance.

5 Likes

I was going bonkers trying to find a solution to this as i have a large bridge and found the same issue.
I will have to attempt to fix this in the morning now as coding when tired is not good.
Thanks :slight_smile:

1 Like

i did not actually get that error, but, it did bug me the fact that, order is not guaranteed. however since it caused me no issues, i decided not to bother. but now, that i looked, and it might cause issues later on, i decided to find a solution for it, and fix it before it happens.

basically, i decided on simply turning it to a list, and then use the Sorting Function. while Creating a new sorting class. this is the one i liked the most.

also i must say very nice clean solution from AviiNL but The Lambda Expressions are so confusing (at least they are to me).
i’ve written an alternative with a normal function instead of the Lambda kind of things. it is messier, but kind of simpler.
please note you’ll need “Using System.Linq;”

though personally, i’ll be using the first method. where i create the Sorting Class, and use a list.

Gotta get more familiar with LINQ :slight_smile:

Privacy & Terms