¿Cuál de estos dos códigos es 'mejor'? ¿Hacer una variable local o una variable de clase?

11

Estoy haciendo más juegos y haciendo más preguntas estúpidas.

Esperemos que este sea muy breve. Estoy haciendo una clase muy básica que simplemente mueve un objeto Player aplicando fuerza a un cuerpo rígido, pero me hizo preguntarme, ¿debería hacer una referencia de clase a la rb o solo una variable local dentro de Actualizar cada cuadro? (teniendo en cuenta que ya existe en la clase monobehaviour.GameObject unity parent).

Me pregunto si hacer muchas variables locales ralentizaría el ciclo en su conjunto (por local quiero decir dentro de la función en sí y no en la parte superior de la clase, espero que esté usando el término correcto).

Esto es lo que quiero decir, las dos formas en que estaba pensando en hacerlo:

public class Player : MonoBehaviour {

private void FixedUpdate()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}

o...

public class Player : MonoBehaviour {
Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

private void FixedUpdate()
{
    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}
Big T Larrity
fuente
44
Esto parece más una pregunta para la revisión de código SE.
Orphevs
1
También podría hacer la propiedad float va class.
Chad
Probablemente, al final, en realidad sea Chad, porque lo usaré en dos métodos dentro de la clase. Realmente era solo un código simple para obtener la pregunta sobre las variables locales vs de clase sin hincharlo con mucho código. Realmente me gusta mantener las variables locales (¡y 'fuera del camino' como donde!) Pero, por supuesto, debo asegurarme de no comenzar a duplicar cosas en lugar de tener una variable de clase para cada una.
Big T Larrity
Un fragmento de código no es 'un código'. Preguntar sobre "qué código es mejor" te hace ver como un aficionado.
Miles Rout
1
soy un aficionado así que está bien conmigo gracias Miles
Big T Larrity

Respuestas:

25

En general, he descubierto que debe abarcar los datos de la manera más estrecha posible para comenzar y ampliar el alcance cuando descubra que lo necesita. Eso significa que si puede convertirlo en una variable local en lugar de un miembro, probablemente debería comenzar allí.

Esto se debe a que un alcance más reducido reduce la cantidad de lugares en el código donde debe razonar sobre esos datos y, por lo tanto, reduce la cantidad de lugares sobre los que puede razonar incorrectamente (lo que genera errores).

En realidad, declarar solo las variables locales nunca va a ser prácticamente un problema de rendimiento: son baratas y los compiladores modernos incluso pueden optimizar los "extras".

Inicializarlos puede ser una preocupación; en su caso, su cuerpo rígido se busca cada vez a través de GetComponent, lo que tiene un costo distinto de cero. Si sabe que el componente del cuerpo rígido no cambiará para este objeto de juego en particular, puede buscarlo una vez y almacenar el resultado en una variable miembro y evitar una pequeña sobrecarga por llamada.

Es poco probable que la sobrecarga por llamada sea significativa en este caso, pero con el tiempo, esto puede sumar para muchos componentes. Desea aplicar un perfilador para estar seguro.

Entonces, para resumir: en general, el valor predeterminado es hacer que las cosas sean lo más locales posible, pero en este caso probablemente sea razonable hacer rbun miembro para que pueda realizar la búsqueda una vez Awakey evitar tener que hacerlo en cada FixedUpdatellamada.


fuente
1
gracias Josh, sentí que sería mejor tener el rb inicializado solo una vez, y muchas gracias por explicar claramente por qué. Es bueno saberlo con certeza, ya ves que no estaba 100% seguro de que GetComponent contara como inicializándolo cada vez, o simplemente 'buscando' desde Monobehaviour. Pero ahora lo entiendo muchas gracias por la respuesta súper rápida y útil
Big T Larrity
1
@SuperMegaBroBro GetComponent es bastante rápido: sería difícil realizar cualquier tipo de búsqueda que tenga una velocidad comparable. A menos que tenga datos de rendimiento que sugieran que es un problema, siga con el enfoque de "mantener las cosas locales". Siempre puedes optimizarlo más tarde. Consulta answer.unity.com/questions/185164/… . No olvides que el almacenamiento en caché tampoco es gratuito: si guardas en caché todos los elementos GetComponentde tu juego, probablemente será una pérdida neta. Medida. Identifique dónde valen las optimizaciones. Centrarse en hacer un gran juego :)
Luaan
1
La esencia principal que debe extraer de esta respuesta (que es bastante buena) es: si desea buscar el código más fácil de razonar, probar y asegurarse de que esté libre de errores, tome la variable local. Pero, como siempre, a veces tenemos que hacer sacrificios para perfeccionar el código por razones de rendimiento, por lo que un miembro de la clase podría ser apropiado (pero el perfil primero, no simplemente optimice prematuramente).
Polygnome
muchas gracias muchachos, especialmente Luaan, ya que me preguntaba sobre ese problema de "almacenamiento en caché" mientras escribía la pregunta original (pero realmente no sabía cómo decir eso). Ciertamente adoptaré el enfoque 'local' tanto como sea posible. Gracias por toda la gran ayuda como muchachos habituales.
Big T Larrity
2

La respuesta de Josh Petrie es muy buena: aquí hay una perspectiva complementaria.

Cuando trabajas con código del que entiendes bastante bien el dominio, puedes abarcar variables donde tengan sentido.

Por ejemplo, si tengo una Personclase con un waveGoodbyemétodo, es posible que mi clase no haya tenido un handobjeto antes y que pueda declararlo localmente waveGoodbye. Ahora, aquí es obvio que una persona tiene una mano, por lo que naturalmente puede declararlo como miembro Personsin pensarlo, pero se aplica el mismo problema.

Si declaras handlocalmente, luego puedes agregar un karateChopmétodo que también requiera una mano. Esto es cuando declarar variables localmente puede volverse problemático, porque los desarrolladores junior a menudo recurren a copiar / pegar la declaración waveGoodbyey ahora tiene el mismo concepto ubicado en dos puntos. Cualquier cambio a handcontinuación debe modificarse en ambos lugares y, por lo tanto, comienza un hormiguero .

Así que en general,

  1. Si tiene confianza en la ubicación de su declaración, diríjase a donde tenga sentido.

  2. Si no está seguro, entonces comience localmente y asegúrese de refactorizar cuando reciba un soplo de reutilización de código.

Editar: Ah, y no cometas el mismo error que tengo de pasar demasiado tiempo averiguando dónde buscar tus declaraciones. Es difícil entender la estructura de sus datos por adelantado, y a medida que escribe su código, la estructura tiene una forma de revelarse.

aaaaaa
fuente
2
Además, tener las cosas ordenadas naturalmente, como todos Persondeberían tener el miembro hand si es relevante en la aplicación, a menudo ayuda a otros desarrolladores (la mayoría de las veces , 6 meses después) a comprender mejor el código. En este caso, parece lógico tener un Rigidbodymiembro suyo Playery, digo más, incluso si eso implica un peor rendimiento. En los videojuegos, ese es un punto relevante a tener en cuenta, pero creo que en el código , para ser claros, a menudo es más importante
aunque el
1
excelentes respuestas gracias chicos. No estoy tratando de sonar como un sabelotodo, pero todas estas respuestas han reafirmado lo que ya estaba pensando, así que por una vez estoy muy feliz y estoy progresando en mis juegos. En este momento estoy haciendo un juego de fútbol en 3D con animaciones adecuadas y todo, haciendo grandes progresos: D pronto estaré aquí necesitando ayuda sobre cómo hacer que sea para 2 jugadores y me atrevo a decir multijugador en línea: D ¡diviértanse chicos y gracias de nuevo!
Big T Larrity