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;
}
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, theSqrt
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 slowSqrt
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
.