26 marzo 2015

Detección de colisiones y escuchando al teclado

Hemos estado trabajando con un proyecto en Java que dibuja una pista de carreras (no muy estético, pero funcional) y luego usamos threads para mover 2 carros.  Hasta allí todo bien, pero no muy divertido que digamos.  Por eso, en este post, vamos a hacer dos cosas: detectar colisiones (para que los "carros" no puedan pasar por los obstáculos ni por encima del otro carro) y escuchar eventos del teclado para poder controlar los carros.  En pocas palabras, nuestro juego por fin va a ser funcional.

Pero como dijo Jack el destripador, vámonos por partes: primero vamos a ver que onda con la detección de colisiones y luego veremos que onda con  el teclado.  Así que sin más preámbulos, arrancamos...

Colisiones
Hacer la detección de colisiones (en otras palabras, ver si un objeto "choca" con otro) es bastante sencillo en Java cuando se usan objetos de la clase Rectangle (por eso los usamos desde el primer momento: era más sencillo dibujar sin ellos, pero nos sirven en este momento) porque tiene un método que revisa si hay colisión. Este método se llama intersects.

Digamos que quiero saber si el Rectangle r1 se intersecta (o colisiona) con un Rectangle r2, puedo usar el siguiente código:

if (r1.intersects(r2)) {
    // Código que se ejecuta si hay colisión
}

Y como podrán imaginar, para revisar múltiples colisiones, puedo usar el operador booleano AND (representado como &&) para ver si dos condiciones se cumplen o el operados OR (representado como ||) para ver si uno de los dos condiciones son verdaderos.

Por ejemplo, si quiero ver si el rectángulo r1 chocó con el rectángulo r2 o el r3, usaría este código:

if (r1.intersects(r2) || r1.intersects(r3)) {
    // Código que se ejecuta si choca con r2 o con r3
}

Esta imagen muestra si hay colisiones entre rectángulos (en otras palabras, si se intersectan):


Escuchando el teclado (KeyListener)
Ya en un post anterior hablé sobre "escuchar" eventos en Java (incluyendo el teclado), pero aquí me concentraré solo en el teclado para completar este proyecto.  Si desea profundizar, sugiero que vea el post Interfaces gráficas 4: Escuchando eventos.

El KeyListener permite recibir lo que ha escrito el usuario en el teclado.  Para usarlo, es necesario agregar, al final de la línea de "public class ..." lo siguiente (esto también aplica para clases internas como las que hicimos en los threads del post anterior):

implements KeyListener

Después de esto, en el constructor (o el método run si estás en un thread), hay que agregar el siguiente código para "despertar" al KeyListener y ponerlo a trabajar:

addKeyListener(this);

Recuerda que el this asocia los eventos que "escucha" del teclado a esta clase.

Después de esto, hay que agregar 3 métodos a la clase

public void keyPressed(KeyEvent e) { }
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }

Estas funciones, al igual que el paint del que hablamos en el primer post de esta serie, son ejecutadas de forma automática: el keyPressed se llama cuando se presiona una tecla, el keyReleased se ejecuta cuando el usuario quita el dedo de la tecla y ésta se levanta y el keyTyped ocurre cuando el usuario presiona y suelta la tecla.  El mas usado de los tres es el keyTyped, que es precisamente el único que vamos a codificar en este ejemplo.

Finalmente, para saber qué tecla presionó el usuario, uso el código:

e.getKeyChar()

(Si te fijas, e es el parámetro que viene en los métodos y es objeto de la clase KeyEvent que tiene información sobre lo que se ha tecleado).

Integrando este rollo con el proyecto
Como explico con más detalle en el video, voy a crear variables para indicar la dirección del carrito: si vale 0 el carrito viaja hacia arriba, 1 a la izquierda, etc.  Para hacerlo más fácil, los voy a hacer constantes porque no quiero que se modifiquen en el código (usando la palabra final al declararlos).

Después de esto, voy a usar el KeyListener para cambiar la dirección del carrito del jugador.  También vamos a hacer que el rumbo del carrito cambie al alterar la coordenada x si se mueve hacia la izquierda o derecha y la coordenada y si va hacia arriba o abajo.

Finalmente hay que revisar si el usuario no chocó con un obstáculo o con el otro jugador.  Si sucede, vamos a poner la velocidad del jugador en un valor negativo para que el carro retroceda hasta "agarrar vuelo".

Aquí les dejo el video donde lo explico y el código fuente completo (bueno, completo hasta este momento) lo pueden descargar aquí.


Agradecimientos
La imagen de Duke evitando colisiones en patineta lo tomé del blog de CPU y la de los rectángulos que se intersectan son de una página de Tufts University.  Y como ha sucedido con los 2 posts anteriores, la idea vino de este libro:



¡Hasta la próxima!
Publicar un comentario
Related Posts Plugin for WordPress, Blogger...