Reputation: 1728
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;
}
Upvotes: 3
Views: 11767
Reputation: 16584
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
.
Upvotes: 11
Reputation: 1076
If you have too many gameObjects and want to find closest object just for one object, instead of checking all objects and comparing them. you can use triggers. Attach a sphere collider to your player and increase it size until it collide any other gameObject.
Don't think that if you use collider it will always be worse. Try it and I think it will be a better way. (but as I said if you have too many objects to check)
Upvotes: 2
Reputation: 1313
EDIT: As Corey suggested this answer does not take into account that the lower Approach is using sqrt, which definitely makes it slower.
I don't think the difference is crucial, but as far as raw speed is concerned, I think the second will be slightly faster, as you are not sorting a whole list (optimal time complexity O(n*log(n))), but only get the one with the closest distance (O(n)).
However, if it isn't a really crucial point in the program, I would always go for the first one... It's just a lot nicer.
Upvotes: 3