What is the most effective way to get closest target

Sajitha Rathnayake picture Sajitha Rathnayake · Oct 15, 2015 · Viewed 8.5k times · Source

What is the most effective and less expensive way to get closest target from these two methods?

Using LINQ

GameObject FindClosestTarget(string trgt) 
{
    GameObject[] closestGameObject = GameObject.FindGameObjectsWithTag(trgt)
                      .OrderBy(go => Vector3.Distance(go.transform.position, transform.position)
                      .FirstOrDefault();
         return closestGameObject ;
}

or this

 GameObject FindClosestTarget(string trgt) 
     {
         GameObject[] gos= GameObject.FindGameObjectsWithTag(trgt);

         GameObject closest=null;
         float distance = Mathf.Infinity;
         Vector3 position = transform.position;
         foreach (GameObject go in gos) {
             Vector3 diff = go.transform.position - position;
             float curDistance = diff.sqrMagnitude;

             if (curDistance < distance) {
                 closest = go;
                 distance = curDistance;
             }
         }

         return closest;
     }

Answer

Corey picture Corey · Oct 15, 2015

The first example uses Vector3.Distance which requires a quite expensive Sqrt operation, while the second uses code that I'd prefer to throw in favor of the simpler LINQ form.

Here's an excerpt from the Unity Scripting API documentation for sqrMagnitude:

The magnitude of a vector v is calculated as Mathf.Sqrt(Vector3.Dot(v, v)). However, the Sqrt calculation is quite complicated and takes longer to execute than the normal arithmetic operations. Calculating the squared magnitude instead of using the magnitude property is much faster - the calculation is basically the same only without the slow Sqrt call. If you are using magnitudes simply to compare distances, then you can just as well compare squared magnitudes against the squares of distances since the comparison will give the same result.

So your scenario is basically exactly why they created the sqrMagnitude property... because Sqrt is an expensive operation that you don't need if you just want to know the order of distance without needing the actual distance for use later.

Personally I prefer this as a third option:

GameObject FindClosestTarget(string trgt)
{
    Vector3 position = transform.position;
    return GameObject.FindGameObjectsWithTag(trgt)
        .OrderBy(o => (o.transform.position - position).sqrMagnitude)
        .FirstOrDefault();
}

Best of both worlds... the simplicity (and quite efficient implementation) of LINQ with no superfluous Sqrt operations to slow you down.

But as always, when you have a question about real-world performance of your code you should do some careful profiling of each method to see which one actually performs better. Sometimes the optimizer throws you a curve ball and transforms horrible C# code into quite effective output.

Incidentally, if you wanted to limit your range to a particular maximum distance, square that distance and compare it to the sqrMaginitude to avoid the evil Sqrt.