¿Por qué Unity usa la reflexión para obtener el método de actualización?

12

¿Por qué la Unidad uso reflexión con el fin de acceder MonoBehaviourmétodos mensaje como Awake, Update, Start, ...?

¿No sería lento usar la reflexión? ¿Por qué no aprovecha otros enfoques como Template Method? Simplemente podría definir los métodos como abstractos en la MonoBehaviourclase base y forzar a las subclases a implementarlo.

Emad
fuente

Respuestas:

20

No lo hace

Cómo se llama la actualización

No, Unity no usa System.Reflection para encontrar un método mágico cada vez que necesita llamar a uno.

En cambio, la primera vez que se accede a un MonoBehaviour de un tipo dado, el script subyacente se inspecciona a través del tiempo de ejecución de scripts (Mono o IL2CPP) si tiene algún método mágico definido y esta información se almacena en caché. Si un MonoBehaviour tiene un método específico, se agrega a una lista adecuada, por ejemplo, si un script tiene definido el Método de actualización, se agrega a una lista de scripts que deben actualizarse en cada cuadro.

Durante el juego, Unity solo recorre estas listas y ejecuta métodos a partir de ellas, así de simple. Además, es por eso que no importa si su método de actualización es público o privado.

En cuanto a las razones por las que se hace de esta manera, en gran medida lo remitiré (al lector) a la respuesta de DMGregory , que se reduce a un equilibrio de dos cosas en competencia:

  1. Optimización del rendimiento
  2. Facilidad de utilización de nuevos desarrolladores

Un nuevo desarrollador solo quiere que funcione y no quiere tener que averiguar "¿cómo conecto esto al sistema de eventos?" pero aún así debería correr rápido con una sobrecarga mínima.

La solución es probablemente la mejor que se puede lograr dentro de estas dos restricciones. O al menos, lo mejor que el equipo de desarrollo de Unity pudo encontrar en ese momento. Puede que nunca lo sepamos.

Draco18s ya no confía en SE
fuente
2
tl; dr mismo proceso, API diferente, más rápido. Pero, ¿por qué no eligieron un método diferente como lo solicitó OP?
wondra
10
No debemos negar la posibilidad de una vieja razón de "mal diseño". Después del lanzamiento del código fuente de c # , los usuarios han encontrado toneladas de errores y decisiones de diseño inexplicables. Algunos gamedevs finalmente pudieron entender esos comportamientos inesperados con los que lucharon durante años.
Ejercicio
Dejando a un lado los aspectos técnicos, esta es una de las primeras cosas que aprenden los recién llegados, por lo que debe ser fácil de agregar u omitir.
Nikaas
66
También puede haber razones históricas para este diseño. Unity comenzó con su propio lenguaje de secuencias de comandos, que luego fueron eliminando gradualmente a favor de C #. Es natural que quisieran seguir usando los mismos patrones, incluso si eso significaba hacer un poco de trampa.
Philipp
3
Creo que podemos responder útilmente "¿Qué logra la Unidad por este medio"? ¿Cuál es la ventaja sobre una colección de métodos públicos abstractos que deben implementarse todos? No podemos responder "¿qué estaban pensando los desarrolladores de Unity?" pero podemos abordar "¿por qué este enfoque es útil para los usuarios del motor?"
DMGregory
10

Simplemente podría definir los métodos como abstractos en la clase base MonoBehaviour y forzar a las subclases a implementarlo.

Una de las ventajas del sistema que utiliza Unity es que no tiene que implementar todos los mensajes de MonoBehaviour, de los cuales hay más de 60 .

Por lo general, solo necesitamos uno o un pequeño puñado de estos métodos. Dado que algunos son específicos de la física 2D / 3D, algunos exclusivos de las cámaras o sistemas de partículas, es muy poco probable que un script los necesite alguna vez.

Al dejar los mensajes que no necesitamos como no implementados, podemos indicar claramente al tiempo de ejecución "ni siquiera se moleste en llamar a OnCollisionStay2D sobre este objeto, no lo necesito"

Esto puede ser una ganancia sustancial de eficiencia. Ahora el motor puede filtrar una lista corta para llamar a Actualizar solo en los ~ 20 objetos en mi escena que necesitan una lógica de actualización personalizada en cada cuadro, y no en todos ~ 200 objetos que componen todo el escenario o solo responden a eventos físicos.

DMGregory
fuente
Solo una pregunta ... hasta donde yo sé (no personalmente), si tiene miles de GameObjects, todos los cuales usan un script con un método de actualización, tiene un impacto significativo en el rendimiento. La alternativa es usar listas e iterar a través de ellas con solo un método de Actualización en un script de administrador, lo que parece ser significativamente más eficaz. ¿Sigue siendo así, o eso ya cambió? - Si nada ha cambiado, implicaría que la forma en que Unity lo hace no está cerca del óptimo en cuanto a rendimiento.
Batalla
44
@Battle lo que describe es coherente con el enlace que Draco18s cita de 2015, y sospecho que sigue siendo cierto. Ser capaz de dejar el método de actualización indefinido en esos miles de objetos es precisamente lo que permite que esta optimización funcione. Si cada MonoBehaviour tuviera un método de Actualización definido a través de una clase base abstracta como se describe en la sección de la pregunta que cité, entonces no tendríamos la capacidad de limitar nuestras llamadas de actualización a solo la iteración de la lista del administrador. Tenga en cuenta que estas preguntas y respuestas no abordan "¿Es óptimo el enfoque de Unity?" pero solo cómo el enfoque actual puede ser beneficioso.
DMGregory
Ah, ya veo, eso tiene sentido. ¡Gracias por la respuesta!
Batalla
@Battle Sigue siendo cierto. Si bien lo que hace Unity es más eficaz que las alternativas, todavía tiene más sobrecarga que una llamada de función normal.
Draco18s ya no confía en SE
@ Draco18s - Sí. Ya implementé un UpdateManager para mis proyectos que se encarga de esa optimización hace mucho tiempo. Solo quería una confirmación de que todavía es necesario / útil.
Batalla