32. Colisiones con enemigos. Perder vidas. Aplicación a MiniMiner (versión 5) (*)

La comprobación de colisiones no es difícil, y además ya tenemos un esqueleto en la clase "Elemento Gráfico": la forma más sencilla es comprobar si se solapan el rectángulo que contiene un elemento gráfico y el rectángulo que contiene a otro:

El fragmento de fuente que se encarga de esto es simplemente así:

/** colisionCon: devuelve si hay colision del ElementoGraf con
 *  un rectangulo dado por sus coordenadas
 */
bool ElementoGraf::colisionCon(int x, int y, int ancho, int alto)
{
    if ((this->posX+this->anchura > x)
        && (this->posY+this->altura > y)
        && (x+ancho > this->posX)
        && (y+alto > this->posY))
      return true;
    else
      return false;
}
 
/** colisionCon: devuelve si hay colision del ElementoGraf con otro
 */
bool ElementoGraf::colisionCon(ElementoGraf e2)
{
    return colisionCon(e2.posX, e2.posY, e2.anchura, e2.altura);
}

Cuando veamos que colisionan el personaje y el enemigo (lo único que vamos a comprobar por ahora), deberemos hacer varias cosas:

  • Restar una vida al personaje. Como hasta ahora no estábamos comprobando vidas, esto supone que añadamos esta posibilidad en la clase "Personaje", con todo lo que implica: un atributo privado "numVidas" y varios métodos para leer su valor ("getVidas"), para restar una vida cuando nos toque el enemigo ("disminuirVidas"), y para volver a las 3 vidas iniciales cuando termine una partida, algo que todavía no permitirá esta versión pero haremos muy pronto ("reiniciarVidas").
  • Actualizar el "marcador", para que muestre el número de vidas actual. Eso supone que nos interesará crear una nueva clase "Marcador", que represente la parte de la pantalla que indica las vidas restantes, la puntuación actual y la mejor puntuación.
  • Recolocar el personaje y el enemigo en su posición inicial, o de lo contrario volverían a chocar en el siguiente "fotograma" del juego, y perderíamos más de una vida. Para eso, crearemos un método "reiniciarPosicion" en ambas clases, que además en el Enemigo cambiará su "incrX" (incremento de X) para que vuelva a su posición inicial, moviéndose también en su misma dirección inicial.
  • Comprobar si el personaje se ha quedado sin vidas, y en ese caso marcaremos la partida como terminada (y reiniciaremos su cantidad de vidas, para que vuelva a tener 3, para cuando podamos comenzar una nueva partida... algo que esta versión del juego todavía no va a permitir).

Eso se convertiría en una función como esta:

void comprobarColisiones() {
  // Colisiones de personaje con enemigo: recolocar y perder vida
  if (personaje->colisionCon( *enemigo ))
  {
    personaje->disminuirVidas();
    marcador->indicarVidas(personaje->getVidas());
    personaje->reiniciarPosicion();
    enemigo->reiniciarPosicion();    
    hard.pausa(100);
    if (personaje->getVidas() == 0)
    {
      partidaTerminada = true;
      personaje->reiniciarVidas();  // Para la siguiente partida
    }
  }  
}

La apariencia ahora sería así:

Y aquí puedes descargar toda esta versión, en un fichero ZIP, que incluye todos los fuentes, las imágenes, el proyecto de Dev-C++ listo para compilar en Windows, y un fichero "compila.sh" para compilar en Linux.