jueves, 19 de marzo de 2015

Migración a Unity 5: cambio de gravedad

En el último artículo dejamos al personaje moviéndose por la escena. Quería como siguiente paso ver si era capaz de hacer una de las partes que tenía hechas en el SuperCharacterController pero no integradas en mi proyecto, las referentes al cambio de gravedad.

Efectos de partículas en el giro de gravedad

Al ser un ejercicio académico lo más importante aquí es aprender. Por eso aunque el trabajo realizado en los cambios del controlador de personaje anterior no se va a usar en el juego final, todo lo que me tuve que pegar con los giros, cuaternios y direcciones de la gravedad me sirvió para aprender y poder realizarlo en el nuevo controlador en menos tiempo. Incluso algunas de las funciones, como la que calcula los ejes más cercanos a un vector las he podido reutilizar.


No encontré ninguna animación que me encajase bien para el cambio de gravedad, así que acabé haciéndola a mano. Es sencilla, como un salto con ambos pies y abrir los brazos mientras gira la gravedad. Dividida en dos animaciones, la parte de ascender y la de girar. Así la máquina de estados de Mecanim me dará los dos estados que necesito para controlarlo en el código.

En la primera versión tenía dentro de la animación la ascensión, y lo único que tenía que controlar por código era el giro. Y esa parte en concreto no es tan difícil, se calcula un cuaternio que represente la rotación deseada al final, y se interpola en cada paso el pequeño giro a dar, teniendo ya hecha la función que compara dos cuaternios para saber cuando hemos llegado lo suficientemente cerca para hacer un último paso de giro poniendo la rotación definitiva.

Más complicado es hacer que el personaje se mueva correctamente con la nueva gravedad. Al finalizar el giro cambio la gravedad global de Unity, por lo que en teoría tendría que afectar a obstáculos, enemigos... o eso espero. El script de control de personaje tenía algunas partes donde usaba cosas ajenas a esa gravedad, siempre en el eje Y, por lo que si tu gravedad está en otro eje, u otra dirección no funciona bien. Así que le tuve que meter mano. Y fue seguramente la parte más complicada. En el controlador anterior todo estaba calculado más a mano, aquí se usan funciones internas de Unity, del tipo de InverseTransformDirection o ProjectOnPlane, que está documentado lo que hacen, pero no explica muy bien cómo lo hace, por lo que no se si está teniendo en cuenta algunas cosas predefinidas como si arriba es Y, cosa que en mi caso no tiene porqué cumplirse. Aún así, a base de pruebas de datos, y con un sistema de matrices de permutación para varias las direcciones en una de las etapas conseguí que funcionase bien. Siempre y cuando la cámara gire junto al personaje, ya que lo que significa “hacia delante” o “derecha” va ligado a la cámara, a lo que ve el jugador. Por eso para las pruebas he hecho que la cámara cuelgue directamente del personaje, así gira con él, a falta de hacer más adelante un sistema de cámara más complejo para los giros que dependa del sistema de cámara sobre raíles que he estado creando.

Como he dicho el movimiento de ascender y una leve levitación estaban hechos directamente en la animación, pero por alguna razón la capsula del personaje no se movía con esa animación. Esto provocaba que si girabas cerca de una pared la cabeza no quedase cubierta por la capsula que calcula las colisiones y la cabeza atravesase la pared. Entonces me acordé de que en el tutorial de mecanim que había seguido se trataba un problema parecido. Creaban una curva en la animación con la altura de la cápsula para que se adaptase al personaje cuando se hacía una bola al saltar, y en el código iban adaptando la altura de la capsula con los datos de la curva. Así que hice lo mismo, crear una curva para cambiar la posición Y de la capsula, y que esta se adapte a la posición del personaje. El resultado no fue el esperado, por alguna razón, al subir la cápsula, el cuerpo del personaje, la malla bajaba, y sigo sin saber bien qué controla ese movimiento, sospecho que algo interno de Mecanim. El caso es que no conseguí que funcionase así.

La solución que dí a este problema fue quitar ese movimiento de las animaciones. Es decir ahora en la animación se ve como coge impulso, y abre los brazos durante el giro, pero ni se eleva ni gira, todos esos movimientos se harán por código. Y aquí viene una nueva duda. ¿cómo elevar el personaje, cuando debe elevarse, y no antes? Porque la animación primero dobla las rodillas para coger impulso, debería elevarse una vez que se ha vuelto a estirar. Intenté hacerlo con curvas, pero el resultado no fue bueno, ya que la curva te da un valor en cada momento, y no puedo dar un valor absoluto a la Y del personaje, así que puedo ir sumando el valor de la curva a su posición Y (es local, no me preocupa la gravedad), pero al finalizar el ascenso el personaje cae, y la forma en que sube no es buena. Cambié la curva por un evento sobre la animación, otro tipo de cosa que no había probado. Marcas un momento en el que quieres que se ejecute algo, script y función y hasta parámetros si quieres. Así que hice que ejecutase una función justo al finalizar la parte de la animación donde coge impulso, para dar impulso al rigidbody del personaje, igual que cuando se salta. Aunque haciéndolo así, caería mientras gira, por lo que hice que la gravedad fuera 0 durante el giro, para comenzar con la nueva gravedad una vez completado.

Con eso ya tengo el giro correcto del personaje y que funcione bien, ahora solo falta poner unos efectos especiales, ponerlo bonito. Quería algo que pareciese un poder del personaje y que se propagase el resto del escenario. He probado los sistemas de partículas que vienen en Unity 5, y algunos de la Asset Store, los he combinado y personalizado. De los de Unity 5 he cogido un subemisor del de explosiones que hace como una onda expansiva. Pero he cambiado de billboard a malla con una esfera. Y de uno de la asset store que es como una magia verde, he cambiado los sprites a azul. Usa un sistema bastante curioso donde se usa una textura con varios sprites y va cambiando de uno a otro, es parecido a trabajar con sprites en 2D o CSS sprites para los que vengan del diseño web. También he quitado sub-emisores y personalizado otros. Y venía con dos luces, me he quedado solo 1 y simplificándola, pero queda bien, da más luz durante el uso de las partículas. Luego he separado todo este lio en 2 sistemas distintos, para poder apagar uno (el de la luz) y que las partículas del otro (las ondas expansivas) no desaparecieran. Con un poco de paciencia, ajustando bien las cosas y eventos, conseguí que quedase bien, es lo que se ve en el vídeo. 


No hay comentarios :

Publicar un comentario