Animation Curves, la palanca de diseño definitiva

Esta es la tercera publicación de blog de Christo Nobbs en su serie para diseñadores de juegos. La serie amplía sus contribuciones al libro de jugadas del diseñador de juegos de Unity , una guía detallada de más de 100 páginas que instruye a los diseñadores de juegos sobre cómo crear prototipos, crear y probar el juego en Unity. Los enlaces a las publicaciones de blog anteriores de Christo se incluyen al final de este artículo.

Animation Curves, la palanca de diseño definitiva
Animation Curves, la palanca de diseño definitiva

Esta es la tercera publicación de blog de Christo Nobbs en su serie para diseñadores de juegos. La serie amplía sus contribuciones al libro de jugadas del diseñador de juegos de Unity , una guía detallada de más de 100 páginas que instruye a los diseñadores de juegos sobre cómo crear prototipos, crear y probar el juego en Unity. Los enlaces a las publicaciones de blog anteriores de Christo se incluyen al final de este artículo.

En Unity, hay varios "tipos" que podemos usar para almacenar datos que son tan beneficiosos como palancas de diseño para equilibrar sistemas, jugabilidad, configuraciones de personajes, perfiles de vehículos, etc. Las curvas de animación son uno de esos tipos de componentes que ofrecen a los diseñadores y creadores de juegos posibilidades interesantes, especialmente al crear prototipos. Úselos en su proyecto, por ejemplo, dentro de un sistema de partículas para controlar las variables animadas, o dentro del componente de fuente de audio para administrar la atenuación y otras propiedades.

Una curva es un gráfico lineal que muestra la respuesta (en el eje Y) al valor variable de una entrada (en el eje X). Unity usa curvas en una variedad de contextos diferentes, específicamente en animación. Los editores de curvas tienen varias opciones y herramientas diferentes que puede aprovechar.

Esta publicación se centrará en trabajar con Animation Curves a través de la API de Unity, con el tipo de variable AnimationCurve . De esta manera, se pueden utilizar para capturar y almacenar datos, lo que es útil para analizar los resultados. Las curvas también son compatibles con ScriptableObjects, que, como se explica en el libro de jugadas , son excelentes para editar datos de juego.

Las curvas de animación se pueden editar dentro del Inspector como variables públicas o cuando se serializan. Puede guardarlos, exportarlos o cargarlos en el modo de edición o en tiempo de ejecución. Las tangentes editables permiten controlar la forma de la curva entre las teclas.

Una propiedad de Curva de Animación en el Inspector
Una propiedad de Curva de animación en el Inspector: al hacer clic en ella, se abre el Editor de curvas, donde puede ajustar la curva y guardarla en su propia biblioteca seleccionando el icono de la rueda dentada.
La clave de una tangente en Unity
Al hacer doble clic en una curva, se crea una nueva tecla que puede usar para manipularla y también ofrece varias opciones para controlar los controles de la tecla.

Puede agregar claves, alterar sus tangentes y manipular los controladores en la curva para encontrar la forma que brindará los resultados deseados.

Una curva de animación con múltiples tangentes
Una curva de animación que incluye tangentes para crear picos, valles y ángulos abruptos orgánicos
Agregar detalles realistas al movimiento y movimiento cotidianos

Una palanca de diseño visual como Animation Curve hace posible que los diseñadores de juegos perfeccionen el juego sin tener que escribir matemáticas complejas o funciones de aceleración . 

Una forma de usar las curvas de animación es en una línea de tiempo, para agregar matices y detalles a los movimientos lineales. Tomemos el ejemplo de un personaje que cierra la puerta de un automóvil. La acción comienza con un tambaleo cuando la mano agarra la palanca para cerrar la puerta. La puerta se cierra lentamente al principio, pero el movimiento se acelera a medida que la puerta se cierra y luego termina con una parada abrupta; tal vez con un pequeño rebote o clic. Todos estos movimientos se pueden guardar dentro de la misma curva para la secuencia.

Una puerta marrón que se abre y se cierra en un gar verde en el editor de Unity
Una puerta abriéndose y cerrándose usando curvas en la línea de tiempo de la animación.
La curva para abrir una puerta.
La curva para abrir una puerta.
La curva para cerrar una puerta.
La curva para cerrar una puerta.

Como muestra este ejemplo, las curvas de animación son beneficiosas para cambiar las propiedades de un objeto con el tiempo para crear un movimiento de aspecto natural. Otros casos de uso se centran en cómo un objeto se mueve o gira, un personaje acelera o desacelera al entrar o salir de un sprint, o un motor entrega energía al controlador de un automóvil.

Curva de animación C# código
Vea esta descripción general de cómo una curva de animación en el Inspector devuelve datos en el eje Y en una posición determinada en el eje X. El método inferior muestra cómo usar el método EvaluateCurve pasando la curva y la posición deseadas.

Cuando crea una Curva de animación para editar en el Inspector, podrá evaluar la curva pasando un parámetro, denominado tiempo en Unity. Más adelante en esta publicación, veremos por qué la posición es más descriptiva cuando no se usa el eje X para el tiempo.

Una "pseudo" curva de par motor para controlar la potencia de salida del motor

Examinemos cómo podría usar una curva de animación para controlar la potencia de salida del motor de un vehículo. Puede crear una "pseudo" curva de par motor para devolver la fuerza aplicada al vehículo en función de las RPM actuales del motor (revoluciones por minuto). Esto aumenta con el tiempo si el jugador presiona el acelerador.

En lugar de mapear el rango completo de RPM para cada marcha y vehículo, puede "normalizar" o establecer las RPM entre 0 y 1. Las curvas de "par" que cree se pueden guardar y reutilizar para otros vehículos y marchas.

Establezca este valor dividiendo su valor bruto o actual por el valor máximo: 

RPM actual normalizado = RPM actual / RPM máximo

La potencia de salida (eje Y) también se utilizará entre 0 y 1 para mantener el editor de curvas manejable y las propias curvas reutilizables. Este valor se puede agregar a la fuerza de movimiento del vehículo, para mover el cuerpo rígido del vehículo hacia adelante en el eje Z.

Un script de ejemplo para normalizar el RPM
Aquí hay una secuencia de comandos de ejemplo para "normalizar" las RPM y luego agregar una fuerza basada en el valor Y de la curva de torque a RPM dadas multiplicadas por la potencia del motor.

Puede crear varios resultados con la misma configuración para otros vehículos manteniéndose entre los valores de 0,0 y 1,1 en la curva.

Una curva verde ascendente
Esta curva muestra un vehículo que tiene un arranque constante a medida que la masa comienza a moverse, pero en la potencia máxima, el motor pierde fuerza, lo que anima al jugador a cambiar de marcha en la posición correcta.

Agregar una ecuación básica de relación de transmisión al motor de su automóvil puede dar como resultado vehículos de aspecto realista que se mueven y balancean a medida que cambia de marcha y alcanza diferentes curvas de potencia, o la misma curva en diferentes puntos. Esto requiere que el coche sea un Rigidbody. A medida que agrega otros Rigidbodies en el maletero o en los asientos traseros del automóvil, el automóvil tendrá un movimiento impactado, lo que puede ser divertido para las misiones de entrega cronometradas.

Si no desea utilizar el sistema de física de Unity porque tiene un controlador de automóvil personalizado, puede crear variantes cargadas y descargadas de sus curvas, e intercambiar estas curvas en tiempo de ejecución para que el vehículo conduzca de la manera que desee.

Aunque no usará esto con frecuencia, puede agregar claves, modificar claves (lo que elimina y agrega nuevas claves) y eliminar claves por completo en las curvas en tiempo de ejecución a través de la API de Unity. Esto le da más control sobre la modificación de sus curvas, lo que también puede incluir suavizar las tangentes según sea necesario.

Curvas para un vehículo pesado, como un camión con cambios automáticos que arranca lentamente pero no pierde potencia después de alcanzar las RPM máximas: esta curva muestra el camión sin carga.
Curvas para un vehículo pesado, como un camión con cambios automáticos que arranca lentamente pero no pierde potencia después de alcanzar las RPM máximas: esta curva muestra el camión sin carga.
Esta curva muestra un camión con una carga pesada.  Al agregar otra llave y una reducción de potencia después de que el vehículo haya comenzado a moverse, puede hacer que el camión se sienta como si tuviera una segunda marcha extendida, por ejemplo, dándole más personalidad.
Mientras tanto, esta curva muestra un camión con una carga pesada. Al agregar otra llave y una reducción de potencia después de que el vehículo haya comenzado a moverse, puede hacer que el camión se sienta como si tuviera una segunda marcha extendida, por ejemplo, dándole más personalidad.
Una sola curva para un vehículo que tiene múltiples marchas
Una sola curva para un vehículo que tiene múltiples marchas, lo que da la sensación de tener marchas automáticas sin implementar un sistema de motor con una caja de cambios: La curva muestra la mayor parte de la potencia en segunda, tercera y cuarta, donde tercera, cuarta y el quinto son marchas más largas, y el quinto continúa por un tiempo antes de alcanzar la velocidad máxima. Se utilizan diferentes tangentes para crear los resultados deseados.

Las curvas de animación le permiten crear excelentes abstracciones de sistemas más complejos que puede controlar en un formato visual. En el ejemplo del motor, puede agregar potencia con el tiempo al acelerar con la curva que se muestra arriba (que representa la "pseudo" caja de cambios) para crear la sensación de que el automóvil cambia de marcha, ajustando su tono hacia arriba a medida que se entrega la potencia y luego hacia abajo. nuevamente a medida que la potencia se apaga en la parte superior de cada engranaje. Esto es ideal para crear prototipos del movimiento de un vehículo colocando toda la potencia del automóvil en una curva que mapea todos los engranajes, desde el inicio de la primera velocidad en x0, y0 hasta la parte superior de la quinta velocidad en x1, y1.

Las RPM generalmente se acumulan con el tiempo al acelerar, por lo que esencialmente está trazando valores a lo largo del tiempo, de manera muy similar a agregar movimiento lineal a un objeto en movimiento. Lea más sobre esto en la sección sobre tiempo y animación en el libro de jugadas del diseñador de juegos .

Tres coches de aspecto futurista compiten en una gran carretera de cuadrícula con luces azules de neón que rodean la carretera
La física "pseudo" es útil en juegos donde el movimiento no se adhiere a las reglas de la física de la vida real, como en el juego de carreras futurista Made with Unity, Antigraviator.

Tomemos otro ejemplo; la suspensión y el movimiento de un automóvil cuando se conduce sobre un terreno irregular, en las esquinas o cuando se entrega potencia a las ruedas. Se puede gestionar una mejor dirección, el control de las fuerzas laterales o el deslizamiento de los neumáticos con las curvas de animación para crear resultados realistas que puede refinar visualmente.

Al crear una mecánica basada en raycast para un vehículo, ya sea un vehículo flotante o con ruedas, una opción común para crear el efecto de "suspensión" en el motor es una fuerza hacia arriba aplicada en cada rayo y un controlador PID (proporcional-integral-derivado). algoritmo para controlar el rebote, o en algunos casos, la ley de Hooke para la amortiguación. Se puede ver un ejemplo de esto en el ciclo 4.2 de Hover Racer Live 7/21 de Unity , junto con un ejemplo más abajo en esta publicación que usa un PID basado en él.

Un algoritmo de controlador PID es un mecanismo de retroalimentación de bucle de control, o un controlador, utilizado en muchas industrias, incluido el desarrollo de juegos, cuando se necesita una corrección receptiva. El controlador PID calcula un valor de error como la diferencia entre una variable de proceso medida y un punto de ajuste deseado y, en relación con la elasticidad (o nuestro ejemplo dado), puede usarse como una alternativa a la ley de Hooke. Un PID en juegos también es práctico para:

  • Hacer que un vehículo regule una velocidad objetivo en el modo de control de crucero, mientras está sujeto de manera impredecible a otros factores como la masa transportada, la entrada del jugador o la angulación del terreno.
  • Controlar la precisión que tienen los agentes de IA enemigos cuando disparan a tus jugadores, mientras evitan ser golpeados.
  • Predicción de latencia en juegos multijugador.

Los PID se pueden usar en cualquier parte del desarrollo de juegos, especialmente en entornos limitados y simulaciones que requieren un " control automático preciso y optimizado ". Kerbal Space Program by Squad usa PID para mantener una nave espacial en una sola dirección.

Según este estudio , “la regulación PID es la tecnología de sistemas continuos más madura y más utilizada” fuera del desarrollo de juegos. Consulte esta lección sobre el sistema de control: Introducción al control PID para obtener información adicional.

Un cohete espacial está en un hangar, con una interfaz abierta a la izquierda que muestra opciones de personalización para el cohete.
Kerbal Space Program de Squad, disponible en Steam, utiliza algoritmos de controlador PID.

Es posible que los algoritmos del controlador PID no tomen mucho tiempo para crearse, pero requieren tiempo para equilibrarse; tiempo que se multiplica dependiendo de cuantos vehículos tengas. Sin embargo, al crear prototipos, puede usar una curva de animación para ahorrar tiempo o evitar los desafíos técnicos de implementar y equilibrar múltiples controladores PID (eventualmente querrá reemplazar la solución de curva con un PID para un control final).

Las curvas son ideales para la creación de prototipos porque se pueden usar para hacer coincidir visualmente ejemplos de referencia de objetivos del mundo real. Cuando se trata de espacio, esto es "matemáticamente perfecto" en un motor de juego, sin fuerzas de movimiento opuestas a menos que se agreguen o que la gravedad predeterminada esté habilitada. Por lo tanto, a menudo es más fácil usar una curva simple para controlar el cambio y obtener buenos resultados.

En el caso de crear la suspensión para un vehículo, puede usar Curvas de animación para informar cuánta fuerza opuesta se aplica según el nivel de compresión del resorte (normalizado entre 0 y 1), en lugar de usar un controlador PID para crear amortiguación. Combinado con un Rigidbody y una pequeña cantidad de arrastre, se suprime la oscilación de rebote y la suspensión del vehículo reacciona al aumento o disminución de la carga.

Para determinar la compresión del resorte, debe restar la distancia de impacto del rayo de la longitud del resorte de 1.0f. Independientemente de su longitud, cuando el resorte está al 25% de compresión, el valor de compresión será de 0,25. Establezca este valor de compresión como el valor X en la curva de animación, multiplíquelo por la fuerza de resorte deseada (porque está trabajando con valores normalizados) y luego utilícelo en AddForceAtPosition para aplicar la fuerza hacia arriba en cada punto de un ciclo, según el número de puntos de suspensión. No se necesitan fuerzas descendentes adicionales además de la gravedad predeterminada de Unity en -9.81f.

Aquí está la fórmula: 

fuerza hacia arriba = multiplicador de fuerza * curva de fuerza. Evaluar (compresión de resorte normalizada);

rigidBody.AddForceAtPosition(hitNormal * upsForce, point.transform.position);

Usando una relación masa: fuerza de 13:110 y la siguiente curva.

Una furgoneta blanca sin ruedas se cae en una carretera frente a un bosque, en Unity
Una camioneta sin ruedas con longitudes de suspensión extendidas (longitud de resorte de 1 metro): La camioneta cae en un ángulo desigual, hacia abajo y se balancea hacia adelante y hacia atrás.
Una doble curva sigmoidal
Vea una curva que se asemeja a una doble sigmoidal en la que la primera fase corta es una curva inversa, seguida de una ligera pendiente negativa al comienzo de la segunda fase. La curva de fuerza, donde X = compresión de resorte normalizada e Y = potencia (0 a 1), se usa para crear un resultado amortiguado en la caída de Rigidbody (el vehículo que se muestra arriba), para simular la suspensión.

El vehículo se asienta con una compresión de aproximadamente el 50 % utilizando valores adecuados de masa, fuerza ascendente y pequeñas cantidades de resistencia lineal y angular para suprimir la oscilación. Esto permite que el vehículo rebote y se asiente, pero no toque fondo, a menos que se deje caer desde una altura extremadamente alta o que el jugador lo sobrecargue agregando masa.

Para encontrar buenos valores, comience con una curva y = b^x (que se parece a un cuarto de círculo). Mantenga el arrastre bajo y ajuste la masa del vehículo a lo que es en realidad. Luego, la fuerza hacia arriba se ajusta hasta que el vehículo se asiente con una compresión del resorte de aproximadamente el 50 %. Deje caer el vehículo varias veces para verificar si toca fondo y ver dónde se asienta después del rebote. El uso de este enfoque para la suspensión de vehículos que conducen sobre terreno irregular, donde cada punto de tracción se puede ganar o perder, lo convierte en un sistema de suspensión rápido y controlable.

El uso de Curvas de animación para su modelo de suspensión puede garantizar movimientos variados para vehículos (automóviles, furgonetas o camiones con mala suspensión), es decir, aquellos que tocan fondo todo el tiempo, rebotan como los de los juegos de arcade o ruedan en las esquinas y se tambalean cuando acelerar y frenar. Las curvas se pueden usar en combinación con los sistemas existentes si aún no está usando el sistema Rigidbody de Unity o su propio método de suspensión. Puede usar las curvas para la dirección o para amplificar la potencia del motor, la suspensión, la resistencia al avance, el deslizamiento de las llantas, la fuerza de frenado y más. Las curvas de animación son una herramienta tan útil y versátil en Unity para agregar palancas de diseño a cada vehículo para controlar sus características visualmente en el Inspector.

Bolas grises cayendo con diferentes características y curvas en Unity
Uso de diferentes curvas para cada Rigidbody para ver las características cuando se suelta
Las curvas de cada esfera en la imagen anterior
Las curvas de cada esfera en la imagen anterior
Un fragmento de código en C# para colocar objetos
El fragmento de código para soltar esferas

La fila de esferas en la imagen de arriba se creó colocando una secuencia de cuerpos rígidos en una fila y restringiendo sus propiedades de posición de congelación X y Z. Luego se aplicó una fuerza hacia arriba utilizando una Curva de Animación basada en la fuerza de compresión hacia arriba, pero con diferentes curvas para cada esfera, colocadas una al lado de la otra para una mejor visualización. Puede usar esta técnica para encontrar el nivel de rebote deseado para un objeto o para ajustar el rebote existente para equilibrar las características. Como diseñador, poder manipular las características de la fuerza ascendente puede ayudarlo a crear abstracciones de funciones más complejas.

Las curvas son un poderoso tipo de datos de gráfico XY y, aunque no son técnicamente perfectos, pueden ayudarlo a crear prototipos de soluciones de amortiguación rápida que se pueden editar visualmente en el Inspector y guardar como ajustes preestablecidos en tiempo de ejecución. En este blog sobre el arte de la amortiguación, Alexis Bacot destaca todas las cosas que “dependen de una buena amortiguación. Cámara, animación, movimiento, gradientes de color, transiciones de interfaz de usuario y mucho más... ¡se usa en todas partes! Comprender la amortiguación es clave para lograr un gran pulido. La amortiguación por sí sola puede marcar la diferencia entre una mala o una buena experiencia”.

En la misma publicación, demuestra cómo se puede usar SmoothDamp de Unity para crear una hermosa entrada y salida, y cómo reacciona con precisión al cambio del objetivo. Pero no rebota como un "amortiguador de resorte avanzado que puede oscilar, lo cual es excelente para la suspensión de automóviles o la física de bolas falsas", un ejemplo en el que las curvas de animación brindan una poderosa ventaja.

Por supuesto, las curvas tienen más usos que un tipo de datos XY para manipular el juego. También se pueden tratar como una herramienta de evaluación para capturar datos visualmente usando AddKey a través de la API de Unity. Para evaluar una posición a lo largo del tiempo, como la amortiguación en el ejemplo de la suspensión del vehículo o las esferas que caen, use AddKey(elapsedTime, currentSpringCompression) en un método y luego llame a ese método y pase captureResolution como la tasa de repetición a través de InvokeRepeating . Una resolución de captura de 0.1f significa que, cada 0.1s, se agrega una clave a la curva. Vea el mini resultado en el Inspector o abra el gráfico para ver los datos completos.

Una curva trazada
Una curva trazada resulta del uso de una curva de rebote lineal que tiene una línea recta directa de 0,0 a 1,1
Una curva trazada
Una curva trazada resulta del uso de una curva sigmoidea doble no lineal, similar a la que se muestra arriba
De vuelta a la furgoneta que rebota

Echemos un último vistazo a la furgoneta que cae. La curva de animación dicta cuánta fuerza se aplica en función de la compresión del resorte y crea un resultado cercano al objetivo, que tendría un poco más de oscilación en el tercer rebote. Puede comparar la suspensión creada con una curva de animación con la del controlador PID, utilizando el PID en Hover Racer Live 7/21 Cycle 4.2 de Unity . La única diferencia es que el resultado de PID se multiplica por la fuerza de desplazamiento en lugar del valor Y de la curva de animación.

Después de implementar el PID y mucho equilibrio, la suspensión del vehículo se siente más cerca del objetivo con menos oscilación de arrastre y menos arrastre necesario para la supresión. Desafortunadamente, el PID debe equilibrarse para cada vehículo si tienen diferentes valores de masa, lo que lleva mucho tiempo. Para fines de creación de prototipos, esto se puede hacer de forma rápida y visual con las curvas de animación, y se pueden analizar los resultados trazados del movimiento. Para evaluar la implementación de PID, nuevamente, puede usar una curva para trazar el resultado en una curva en blanco. El resultado es mucho mejor, con un segundo rebote ligeramente exagerado, pero proporcionando el movimiento y la apariencia que desea para una camioneta grande y flotante.

Una furgoneta blanca sin ruedas suspendida en el aire, en Unity
La implementación final de la suspensión del vehículo utilizando PID, pero basada en las curvas de animación desarrolladas durante la creación de prototipos: la suspensión aún es exagerada, utilizando longitudes de resorte de 1 metro.
Una curva de amortiguación objetivo a la izquierda, con una curva de resultado trazada a la derecha
Vea el resultado de la curva de amortiguación objetivo de Alexis Bacot a la izquierda y el resultado trazado del movimiento del vehículo después de implementar el PID a la derecha.

Para recapitular, use Curvas de animación cuando desarrolle el movimiento del vehículo para: 

  • Trace la salida de la potencia del motor de un vehículo y produzca una progresión de potencia uniforme.
  • Cree movimientos de frenado realistas, como cuando la fuerza de frenado se aplica rápidamente y luego se reduce con el tiempo para simular el frenado de un automóvil real; o, en un juego como iRacing , donde el conductor frena en el límite de la llanta para que el automóvil disminuya la velocidad en un corto período de tiempo sin perder el control.
  • Simule un sistema de suspensión que proporciona las fuerzas ascendentes para el automóvil.
  • Simule la tracción lateral, con cálculos de contrafuerza lateral que evitan que el automóvil se deslice demasiado hacia la izquierda o hacia la derecha.
  • Simule la dirección cuando use un controlador (la dirección se puede usar cerca del medio, alrededor de -0.5 a 0.5, pero se vuelve progresivamente más rápida cuando la posición de la palanca se acerca a -1 o 1).
Un bloque verde flotando sobre agua azul, rodeado de montañas, en Unity
En este prototipo, se usa curve.Evaluate(time) para mover la transformación de la plataforma en el eje Y a lo largo del tiempo.

Además de la física del vehículo, las curvas de animación se pueden usar como palancas de diseño para crear prototipos del movimiento del jugador, daños por golpes a lo largo del tiempo y más. Como una poderosa herramienta de creación de prototipos, Animation Curves permite a los diseñadores de juegos probar la aplicación de fuerza variable e identificar la "sensación" correcta para la mecánica, sin tener que escribir algoritmos complejos o cálculos físicos.