Desarrollo de un videojuego de naves en HTML5 – Parte 5: Trayectorias

Me cuesta cumplir la palabra. Dije que no iba a agregar nada por un tiempo al ejemplo del videojuego de naves en HTML5, pero se me ocurrió algo muy simple y didáctico que le aporta mucho al ejemplo. Así que aquí está, en esta sexta entrega.

Por el momento, las naves enemigas se mueven hacia abajo y en línea recta. ¿Bastante aburrido no? Sería mucho más entretenido si pudieran tener una trayectoria de movimiento. Para poder lograr este objetivo, será necesario usar una de las herramientas más potentes de que disponen los programadores: la matemática.

El código fuente completo de este ejemplo está aquí. Y el ejemplo terminado lo pueden encontrar en el siguiente enlace: Videojuego de naves en HTML5 – Trayectoria

Antes de hacer nada, como siempre, hay que pensar. ¿Qué tipo de trayectoria queremos? ¿Cómo nos gustaría que se muevan las naves enemigas? Opté por un movimiento ondulatorio o de vaivén, como se ve en la siguiente imagen.

sinusoide

Pensando la trayectoria

En el orden de razonamientos que uno tiene en el cerebro, primero piensa en cómo quiere que se mueva y luego se pregunta: ¿Cómo hacer para que se mueva así? Tal vez de entrada no sea fácil darse cuenta. Pero hay algunas ideas sueltas que nos pueden ayudar.

  • El movimiento en el eje y va a seguir igual: la nave no irá ni más rápido ni más lento. Tampoco se alterará la dirección porque sigue avanzando hacia abajo. Por lo tanto, en el eje y no hay que realizar ningún cambio.
  • Ahora hay que considerar un movimiento en el eje x. Un movimiento que parece complicado, porque no debe avanzar hacia uno de los costados, sino que debe ir y luego volver y no de forma lineal, sino que tiene que desacelerarse cuando llega a los extremos horizontales de la trayectoria.
  • Si hemos hecho una correcta separación de capas en el desarrollo, entonces con modificar el movimiento en el modelo debería bastar para que la vista se adapte automáticamente. Y de hecho, así es. El resto del código no deberá ser alterado para que esto funcione de forma correcta.

Sabemos que el movimiento del alien en el modelo está en el método avanzar de la clase Alien:

Muy sencillo. Simplemente se incrementaba la posición del alien en el eje y. Empecemos a buscar elementos de la matemática que puedan ser de utilidad para cambiar esto.

Funciones matemáticas para trazar trayectorias

Sabemos que el alien vive en un plano de dos dimensiones (x e y). Evidente e inevitablemente serán las funciones matemáticas las que nos ayudarán a hacerla mover de acuerdo a una trayectoria determinada. En este caso, la que mejor se parece al vaivén es la conocida función seno, perteneciente a las trigonométricas.

La función seno varía según el valor de un ángulo de un triángulo rectángulo, dando resultados en un rango acotado. Seamos más específicos: toma un valor entre 0 y 2Π (2 “pi”) (rango de valores posibles para un ángulo) y devuelve un número entre -1 y 1. Si variamos un ángulo entre 0 y , le aplicamos la función seno y lo vemos el gráfico, nos dará algo así.

funcion-seno

Si nos pasamos de 2Π, o si vamos para atrás del 0, obtendremos siempre el mismo resultado. La sinusoide, nombre que recibe ese gráfico, se repite infinitamente hacia atrás y hacia adelante. Noten que en los bordes, arriba se llega a 1 y abajo a -1. Nunca se pasa de esos valores.

Alguien, a lo largo de tantos años de historia, se encargó de estudiar esto y descubrió algunas propiedades de este tipo de funciones que tienen la forma:

y = a * sen(c * x)

  • Si se multiplica toda la función por un número como en este caso con a, el resultado que todo el término devuelve varía entre 0 y a. A esta constante que se le antepone a la función se le suele llamar amplitud.
  • Si se agrega una constante que multiplique a la variable x como en este caso es c, entonces la sinusoide se repite más veces en menos tiempo.

Por ejemplo, con y = 4* sen(x)

senoidal-1

Y con y = 4* sen(2*x)

senoidal-2

Observen cómo se comprime el gráfico en el segundo caso. La inclusión del 2 multiplicando provoca este efecto. Noten que en ambos, se llega al número 4 porque este es el número que multiplica toda la función.

Adaptando la matemática al programa

Ya sabemos cómo es la función seno. Ahora hay que aprender a utilizarla. Vamos a crear un nuevo método que se va a llamar avanzarSenoidal sin borrar el método avanzar que ya tenía Alien.

Lo primero que se necesita es una variable que simule el valor de los ángulos. Alguien que actúe de x, digamos. Para ello, basta con crear cualquier variable y hacerla valer entre 0 y . Cada vez que entremos al método, esta variable  que será un atributo, deberá ir incrementando su valor. ¿En cuánto incrementarlo? Es una buena pregunta y vamos a detenernos en esto.

El método avanzarSenoidal será llamado en cada ciclo de juego y debe recorrer entre 0 y 2Π. Recuerden que Π vale 3.1415…, es decir que  equivale a 6,283 aproximadamente. Entonces, si incrementamos en 1 este atributo, en 6 ciclos ya casi habremos terminado la función. Si tenemos en cuenta que en un segundo se ejecutan muchos ciclos, no parece una buena idea. Cuando hice el ejemplo, tuve esta duda y me di cuenta que conviene incrementarlo en 0,05. Este número no sale de hacer magia ni de hacer cálculos (aunque podrían hacerse). Lo obtuve a prueba y error.

Llamemos a este nuevo atributo tperiod.

Deberá incrementarse en 0,05 y variar únicamente entre el rango 0 y . Para hacer esto, se utiliza la siguiente estructura de código.

El objetivo de esa estructura es que tperiod varíe una y otra vez entre 0 y 2Π.  El atributo tperiod comienza en 0. Si es menor o igual que , se incrementará en 0,05; si no, significa que se pasó de de ese valor, entonces vuelve a valer 0. Noten que se usa la constante Π de la clase Math de Javascript (Math.PI) en lugar de poner el valor aproximado. Math es una clase del lenguaje con algunos atributos y métodos útiles para el trabajo con matemática.

Es a tperiod al que le debemos aplicar la función seno. Esta función está incluida en la clase Math y se puede utilizar con Math.sin().

Ahora, pensemos un poco. Si le aplicamos el seno a tperiod, ¿obtenemos el valor en x del alien? Recordemos que el resultado de un seno es un valor entre -1 y 1. Pero nuestra área de juego está entre 0 y  el ancho del canvas. Si le ponemos un número que multiplique antes, podremos ampliar el rango, pero estaríamos modificando la amplitud de la sinusoide. Por otro lado, el valor devuelto estaría siempre dentro de un rango que tiene números positivos y negativos. Por ejemplo, entre -4 y 4, -12 y 12, -300 y 300.

Una mejor idea es tomar el valor que se obtiene de aplicarle seno a tperiod como si fuera una desviación de su posición natural. Es decir que, le sumaremos el valor (sea positivo o negativo) al atributo posx que indica la posición en x del alien.

desviacion

Llamaremos desviacion a esta nueva variable que será local. Su valor será el que se obtenga de aplicarle seno a tperiod y, en este caso, multiplicarlo por 3. Pueden hacer la prueba y probar con otros valores para modificar la amplitud. También pueden introducir un número que multiplique a tperiod para aumentar la frecuencia de oscilación del alien.

A continuación, hay que sumar esta desviación a la posición en x del alien.

Y finalmente, no debemos olvidarnos de incrementar el alien en la posición y, para que avance hacia abajo.

A continuación, tienen el método avanzarSenoidal completo.

Conclusiones

Para trazar trayectorias de objetos no hay mejor herramienta que la matemática. Tener un dominio de ella es una gran ventaja para cualquier programador. Temas como funciones y trigonometría, que hemos visto en este artículo, son fundamentales para poder representar elementos en dos dimensiones.

Por otro lado, más allá de la inclusión de frameworks, es siempre bueno tener un conocimiento completo del lenguaje base. Como vieron, la clase Math tiene funciones muy útiles.

Finalmente, me gustaría comentarles que, a veces, cuando se trabaja con números reales, como en este caso, se dan errores producto de la forma en que el lenguaje maneja estos tipos de números. Cuando el nivel de precisión se transforma en un problema, conviene dejar los tipos de datos nativos y utilizar la clase Number para manejar números.

Soy programador web y me desempeño como Líder Técnico en Polar Bear Development. Trabajo con tecnologías como PHP, Javascript, MySQL y HTML5 para el desarrollo de sitios y sistemas web. Me especializo en Zend Framework 2 y otros frameworks MVC, como también en WordPress y otros CMS. Lidero equipos de desarrolladores trabajando con Scrum. Vivo en Buenos Aires, Argentina.
 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *


*