c# - una - ¿Cuál es la forma más efectiva de obtener el objetivo más cercano?
objetivos especificos verbos (3)
EDITAR: Como Corey sugirió que esta respuesta no tiene en cuenta que el enfoque más bajo está usando sqrt, lo que definitivamente lo hace más lento.
No creo que la diferencia sea crucial, pero en lo que respecta a la velocidad bruta, creo que la segunda será un poco más rápida, ya que no está ordenando una lista completa (complejidad de tiempo óptima O (n * log (n))) , pero solo consigue el que tenga la distancia más cercana (O (n)).
Sin embargo, si no es un punto realmente crucial en el programa, siempre elegiré el primero ... Es mucho más agradable.
¿Cuál es la forma más efectiva y menos costosa de obtener el objetivo más cercano de estos dos métodos?
Usando LINQ
GameObject FindClosestTarget(string trgt)
{
GameObject[] closestGameObject = GameObject.FindGameObjectsWithTag(trgt)
.OrderBy(go => Vector3.Distance(go.transform.position, transform.position)
.FirstOrDefault();
return closestGameObject ;
}
o esto
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;
}
El primer ejemplo usa Vector3.Distance
que requiere una operación Sqrt
bastante costosa, mientras que el segundo usa código que prefiero arrojar a favor de la forma LINQ más simple.
Aquí hay un extracto de la documentación de la API Unity Scripting para sqrMagnitude
:
La magnitud de un vector v se calcula como
Mathf.Sqrt(Vector3.Dot(v, v))
. Sin embargo, el cálculo deSqrt
es bastante complicado y lleva más tiempo de ejecución que las operaciones aritméticas normales. Calcular la magnitud al cuadrado en lugar de usar la propiedad de magnitud es mucho más rápido: el cálculo es básicamente el mismo sin la llamadaSqrt
lenta. Si está utilizando magnitudes simplemente para comparar distancias, entonces puede comparar las magnitudes cuadradas con los cuadrados de distancias, ya que la comparación dará el mismo resultado.
Así que su escenario es básicamente el motivo por el que crearon la propiedad sqrMagnitude
... porque Sqrt
es una operación costosa que no necesita si solo quiere saber el orden de la distancia sin necesitar la distancia real para usarla más adelante.
Personalmente prefiero esto como una tercera opción:
GameObject FindClosestTarget(string trgt)
{
Vector3 position = transform.position;
return GameObject.FinndGameObjectsWithTag(trgt)
.OrderBy(o => (o.transform.position - position).sqrMagnitude)
.FirstOrDefault();
}
Lo mejor de ambos mundos ... la simplicidad (y la implementación bastante eficiente) de LINQ sin operaciones Sqrt
superfluas para ralentizarlo.
Pero como siempre, cuando tiene una pregunta sobre el rendimiento en el mundo real de su código, debe hacer un perfil cuidadoso de cada método para ver cuál funciona mejor. A veces, el optimizador te lanza una bola curva y transforma el horrible código C # en una salida bastante efectiva.
Por cierto, si quieres limitar tu rango a una distancia máxima particular, cuadra esa distancia y compárala con sqrMaginitude
para evitar el malvado Sqrt
.
Si tiene demasiados gameObjects y desea encontrar el objeto más cercano solo para un objeto, en lugar de verificar todos los objetos y compararlos. puedes usar disparadores Adjunte un colisionador de esfera a su reproductor y aumente su tamaño hasta que colisione cualquier otro gameObject.
No piense que si usa colisionador siempre será peor. Pruébalo y creo que será una mejor manera. (pero como dije si tienes demasiados objetos para verificar)