Unity: Update Versus FixedUpdate

Otro artículo sobre cuándo usar los métodos Update y FixedUpdated.

TD;LR: Tener, con bastante facilidad, recreado el problema de mezclar y hacer coincidir timesteps, he convencido a mí mismo que debo poner todo el estado del juego en FixedUpdate métodos.

Antes de entrar en el fondo de este artículo, quería aclarar por qué estoy interesado en Unity en primer lugar:

  • NO tengo mucho interés en jugar o crear videojuegos
  • SÍ tengo interés en crear herramientas útiles (he sido desarrollador web durante MUCHOS años)
  • NO soy uno de los primeros en adoptarlas
  • Unity es una solución BIEN ESTABLECIDA para crear experiencias 3D multiplataforma

Con todo esto en mente, construir soluciones prácticas de Realidad Aumentada (RA) basadas en la web con Unity es algo que necesito aprender.

En cuanto a aprender Unity, NO encontré particularmente útiles los tutoriales oficiales de Unity. Encontré que el curso de Udemy Aprende Unity 3D para principiantes Absolutos era excelente.

Estaba navegando por los materiales y me encontré colgado en la Diferencia de lección entre Actualización y Actualización fija. Investigando un poco más, el quid del problema era que no entendía la siguiente lógica.

Update (); Used Se usa para actualizaciones regulares como: Mover objetos no físicos

FixedUpdate (); Used Se usa para actualizaciones regulares como: Ajustar objetos de Física (Rigidbody)

Tutoriales oficiales de Unity — Update y FixedUpdate — Unity

Un poco más de investigación:

En conclusión, coloque toda la lógica del juego en Update o FixedUpdate. No mezclar y combinar timesteps a menos que usted está dispuesto a morder la bala y aceptar algunas tartamudeo. Además, vale la pena considerar poner todo el estado del juego en FixedUpdate, usando Update exclusivamente para la entrada del usuario, los efectos visuales y la interpolación entre los estados del juego. Si bien esto requiere un cambio en la forma en que estructuras tus juegos, es una estructura de diseño probada con muchas ventajas.

— KinematicSoup — Timesteps y conseguir un Movimiento Suave en la Unidad

Un video clip en el artículo ilustra el problema de mezclar y hacer coincidir timesteps.

Antes de seguir este consejo quería recrear el problema de mezclar y hacer coincidir timesteps por mi cuenta.

La versión final del proyecto que utilicé para escribir este artículo está disponible para descargar.

Update Versus FixedUpdate

Necesitamos comenzar con una comprensión básica de la diferencia entre los métodos Update y FixedUpdate. Para ilustrarlo, creamos un objeto de juego vacío llamado Setup y agregamos el siguiente componente de script:

Assets / Setup.cs (incompleto)

Nuestra salida de consola después de 3 segundos parecía:

Observaciones:

  • Actualización se llama antes de cada representación, la frecuencia (velocidad de cuadro), de los cuales varía en función de la complejidad de la representación y el dispositivo host. Los ordenadores potentes pueden alcanzar velocidades de fotogramas superiores a 150 fps; mi ordenador de desarrollo funcionaba a unos 50 fps. Por debajo de 30 fps, se considera una mala experiencia.
  • FixedUpdate se llama antes de cada actualización interna de física (mover cosas debido a la física, por ejemplo, gravedad). El paso de tiempo fijo de Unity es por defecto 0.02; lleva a que se llame a FixedUpdate 50 veces por segundo.

Simular Velocidad de fotogramas lenta

Para simular una velocidad de fotogramas lenta (10 fps), actualizamos la configuración.script cs de la siguiente manera:

Assets/Setup.cs (incompleto)

Nuestra salida de consola después de 3 segundos parecía:

Observaciones:

  • Ajuste de vSyncCount a 0, se deshabilita la Unidad de sincronización de renders y velocidades de actualización de pantalla.
  • La velocidad de fotogramas real puede ser inferior a TARGET_FRAME_RATE debido a las limitaciones del dispositivo host y la complejidad del renderizado.

Animación manual

Para observar el efecto de varias animaciones, comenzamos colocando un cubo fijo como referencia.

We add our first animated GameObject (Sphere) in front of it with the following script component.

Assets/Sphere.cs (incomplete)

Running it with the normal frame rate:

Running it with 10fps frame rate:

Observations:

  • Obviamente, tenemos un problema. No queremos que la velocidad de animación dependa de la velocidad de fotogramas.
  • El problema es que estamos configurando la VELOCIDAD para que sea de 0,1 unidades / cuadro; queremos que la velocidad se mida en unidades / segundo.

La solución es proporcionar la VELOCIDAD en las unidades de unidades / segundo; 0.1 unidades / cuadro * 50 cuadros / segundo = 5 unidades / segundo. Entonces usamos el Tiempo.deltaTime para saber la hora desde la última llamada para actualizar. Entonces la distancia recorrida es VELOCIDAD * deltaTime.

Activos/Esfera.cs (incompleto)

Con esta corrección en su lugar, obtenemos la misma animación independientemente de la velocidad de fotogramas (pero con 10 fps, es desigual como se esperaba).

después de Haber utilizado la reducción de la velocidad de fotogramas para ilustrar la necesidad de proporcionar la velocidad en unidades / en segundo lugar, podemos comentar las líneas en la Instalación.cs que simulaba una velocidad de fotogramas lenta.

Animación en Física

En lugar de animar manualmente un objeto de juego, podemos animarlo aplicándole física. Podemos animar un cilindro (moviéndose a la derecha por 5 unidades / segundo) mediante:

  • Creando un Plano (llamado Plano)
  • Creando un Cilindro (llamado Cilindro)
  • Agregar un componente de Cuerpo rígido al Cilindro (y congelar la rotación en todas las direcciones)
  • Crear un material de física, Resbaladizo, sin fricción y aplicarlo tanto al Cilindro como al Plano
  • Cilindro de inicio con una velocidad inicial utilizando un componente de script

Activos/Cilindro.cs

Con esto en su lugar, podemos ver que la esfera y el cilindro se mueven a la derecha a la misma velocidad.

Observaciones:

  • La Esfera de la posición se actualiza inmediatamente antes del render (manualmente en el método de Actualización)
  • El Cilindro de la posición se actualiza en el interior de física de la actualización.

Animación con Animación

Una tercera forma de la animación de un GameObject es con una animación (obviamente). Podemos animar una cápsula (intentando moverse a la derecha 5 unidades / segundo) mediante:

  • Creando una cápsula (llamada Cápsula)
  • Creando un controlador de animación (también Cápsula) y agregándolo como componente al objeto de juego de la Cápsula.
  • Crear una animación (también Cápsula).
  • En el controlador de animación, cree un estado (Inicio) con su movimiento para que sea la animación de la Cápsula.
  • Finalmente, animamos la posición para que la posición horizontal de la cápsula sea de 5 unidades en 1 segundo.

Con esto en su lugar, podemos ver que la esfera, el cilindro, la cápsula (casi) se mueven a la derecha a la misma velocidad.

Observaciones:

  • No sé por qué, pero la Cápsula se movió un poco más rápido de lo esperado; problemas de tiro para un rato y no averiguar por qué.
  • La posición de la cápsula se puede configurar para actualizarse antes del renderizado (predeterminado) o durante la actualización de física.

Implicación de una velocidad de fotogramas rápida

En ordenadores potentes, se pueden alcanzar velocidades de fotogramas de hasta 150 fps. En estos equipos con las actualizaciones de física predeterminadas 50 veces por segundo (0,02 segundos entre actualizaciones), los elementos que se actualizan antes de cada renderizado se actualizan con más frecuencia que los que se actualizan en las actualizaciones de física. Esta discrepancia es la fuente de problemas para mezclar y hacer coincidir los intervalos de tiempo.

Aunque no puedo aumentar la velocidad de fotogramas de mi máquina de desarrollo (limitada a unos 50 fps), puedo ralentizar artificialmente las actualizaciones de física a 10 actualizaciones por segundo (0.1 segundo entre actualizaciones) usando la configuración del proyecto.

Como puede ver, mezclando y emparejando timesteps hemos recreado el problema (inconsistente movimiento entre GameElements).

Para corregir, podemos cambiar la animación de la Cápsula para actualizar las actualizaciones de física, y también actualizar el componente de script de la Esfera de la siguiente manera:

Assets / Sphere.cs

Con esto, todas las animaciones se actualizan constantemente antes de cada actualización de física.

por último, volvemos a nuestros física de actualización que se va a 50 fps (o cada 0.02 segundos); el logro de ambos consistentes y las actualizaciones oportunas.

Conclusiones

Tener, con bastante facilidad, recreado el problema de mezclar y hacer coincidir timesteps, he convencido a mí mismo que debo poner todo el estado del juego en FixedUpdate métodos.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.