Después de un tiempo de descanso, es hora de retomar este paso a paso para realizar nuestros juegos con HTML5 y JavaScript.
En esta oportunidad hablaremos sobre una de las características básicas de todo juego, las colisiones.
Detectar colisiones en un videojuego es una tarea común, no solo para poder saber si dos objetos del juego se tocan, como por ejemplo, una bala disparada por nuestro personaje impactando contra un enemigo, sino que además, la interacción con el puntero del ratón, o los dedos en una pantalla táctil para acceder a un determinado menú del juego también representa una colisión.
Existen muchos métodos para detectar que dos objetos se están tocando, cada uno de estos más eficientes que los otros en determinados casos. Podemos encontrar colisiones en forma de caja (La que usaremos para el ejemplo), por píxeles, verificando que solo píxeles de color de un objeto estéen tocando los píxeles del otro objeto, mediante proyección de líneas (Ray Casting), y muchos otros métodos.
La colisión por cajas, entonces, es una de las más simples y puede resultar efectiva si nuestro juego no cuenta con gran cantidad de elementos para detectar si están en colisión o no, ya que si bien no es dependiente de este tipo de colisión, se suele hacer un escaneo por todos los elementos del juego y verificar, uno a uno, si nuestro objeto están en contacto con otro.
Para entender la mecánica de esta forma de detectar colisiones, pensemos en nuestro objeto de juego al cual le dibujamos una caja que lo contenga. Esta caja poseerá tanto las coordenadas X e Y donde se sitúa, además de las dimensiones de ancho y alto. Luego, teniendo el objeto contra el cual probar la colisión, dibujaremos otra caja con datos similares. Cuando ambas cajas entran en contacto, entonces entendemos que existe una colisión.
Este tipo de colisiones no promete detectar correctamente la misma si las formas son irregulares.
Como vemos en la imagen, si las formas (Gráficos) son irregulares, al crearse una caja para contenerlo, puede quedar mucho espacio sin uso, pero que será tomado como válido para la colisión. Para mejorar este comportamiento, una colisión por píxel sería más adecuada, ya que la misma detectará solo aquellos píxeles de color y no los transparentes en nuestro sprite, por supuesto, realizar el cálculo para dicha detección resulta algo más costosa en cálculos computacionales.
Entonces, para detectar mediante la colisión por cajas necesitamos saber las coordenadas de los dos objetos además de sus dimensiones. Una excelente solución es la que nos propone Matthew Casperson con su clase Rectangle en JavaScript.
function Rectangle()
{
this.left = 0;
this.top = 0;
this.width = 0;
this.height = 0;
this.startupRectangle = function(left, top, width, height)
{
this.left = left;
this.top = top;
this.width = width;
this.height = height;
return this;
}
this.intersects = function(other)
{
if (this.left + this.width < other.left)
return false;
if (this.top + this.height < other.top)
return false;
if (this.left > other.left + other.width)
return false;
if (this.top > other.top + other.height)
return false;
return true;
}
}
La sección más importante está dentro de la función intersects, la cual toma los dos rectángulos y compara los mismos para saber que una parte del primero se encuentre en alguna parte del segundo.
Para este ejemplo, dibujaremos un rectángulo en el trayecto de nuestro personaje. Cuando el mismo toque dicho rectángulo, este dejará de avanzar.
contextBuffer.save(); contextBuffer.fillStyle = "black"; contextBuffer.fillRect(300, 10, 30, 40); contextBuffer.restore();
A continuación del dibujado de nuestro personaje, dibujamos un rectángulo de color negro. Podemos notar en el código que estamos utilizado dos funciones, save y restore. Estas funciones sirven para guardar el estado del lienzo de dibujo en ese momento, poder realizar cualquier modificación, agregar elementos, y luego retornar el lienzo al estado anterior. De esta forma, el cambio de color mediante fillStyle no afectará otras funciones que usen este color para rellenar formas.
El bloque negro se interpone en el camino de nuestro personaje.
El siguiente paso, para detectar la colisión será verificar el estado de los dos objetos tras cada actualización del juego.
var boxBlock = new Rectangle(); boxBlock.startupRectangle(300, 10, 30, 40); var boxYoda = new Rectangle();
Debido a que sabemos de antemano la posición del rectángulo negro, no es necesario actualizarlo cada vez que el juego se modifica, por lo que escribiremos el código anterior fuera del bucle principal del juego. Finalmente, en el bucle, comprobaremos la posición actual del personaje y su intersección con el bloque.
boxYoda.startupRectangle(x, 10, 42, 39);
if (!boxYoda.intersects(boxBlock)) {
x++;
}
Solo si el personaje no está en colisión con el bloque, podrá avanzar un píxel.
Como decíamos, este tipo de comprobación suele ser costosa, pero eficiente para darnos una solución rápida para nuestros juegos.







