Colisiones
Uno de los aspectos importantes en el desarrollo de un juego es la detección de colisiones entre los diferentes elementos del juego. En este caso, vamos a implementar la detección de colisiones entre el jugador y los objetos que caen desde la parte superior de la pantalla.
Para nuestro juego, vamos a realizar una detección de colisiones simple, basada en la posición de los elementos en pantalla. Si el jugador y un objeto ocupan la misma posición en pantalla, se considerará que ha ocurrido una colisión.
Para ayudarnos, vamos a utilizar una clase auxiliar llamda Collidable, que nos permitirá definir los elementos que pueden colisionar en el juego. Esta clase tendrá propiedades como la posición del elemento en pantalla y un método para comprobar si ha ocurrido una colisión con otro elemento.
Vamos a definir la clase Collidable en el fichero collisions.h:
#ifndef COLLIDING_H
#define COLLIDING_H
#include <Arduboy2.h>
class Collidable{
private:
Rect collider;
public:
Collidable(byte x, byte y, byte width, byte height);
~Collidable();
void setCollider(byte x, byte y, byte width, byte height);
bool isColliding(Arduboy2Base* arduboy, Collidable collider2);
};
#endif
Y por otro lado, vamos a implementar la clase Collidable en el fichero collisions.cpp:
Collidable::Collidable(byte x, byte y, byte width, byte height) {
this->collider = { x, y, width, height };
}
Collidable::~Collidable() {
}
bool Collidable::isColliding(Arduboy2Base* arduboy, Collidable collider2) {
return arduboy->collide(this->collider,collider2.collider);
}
void Collidable::setCollider(byte x, byte y, byte width, byte height){
this->collider= {x,y,width,height};
}
Esta clase nos permitirá definir los elementos que pueden colisionar en el juego, y comprobar si ha ocurrido una colisión entre dos elementos. Para ello, utilizamos la función collide de la librería Arduboy2, que nos permite comprobar si dos rectángulos se superponen en pantalla.
Es importante mencionar que esta clase será una clase padre tanto para el jugador como para los objetos que caen desde la parte superior de la pantalla, ya que ambos elementos pueden colisionar entre sí. De esta forma, podremos utilizar la clase Collidable para definir las propiedades y métodos necesarios para la detección de colisiones en nuestro juego.
Vamos a modificar la clase Jugador para que herede de la clase Collidable, y así poder utilizar el método isColliding para comprobar si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla.
// player.h
...
class Player: public Collidable{
...
En la definición de la clase Jugador, haremos que herede de la clase Collidable, y así podremos utilizar el método isColliding para comprobar si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla.
Por último, en el método Update de la clase Jugador, vamos a comprobar si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla. Si ha ocurrido una colisión, podemos restar una vida al jugador o aumentar su puntuación, dependiendo del tipo de objeto con el que haya colisionado.
void Player::Player : Collidable:: Collidable(x,y,16,16){
this->x = x;
this->y = y;
this->lives = 3;
this->score = 0;
}
...
void Player::Update(Arduboy2Base* arduboy, ObJ* objects, int numObjects) {
// Actualizar la posición del jugador
...
this->setCollider(this->x,this->y,16,16);
}
Ahora, actuaremos de la misma forma para la clase ObJ, haciendo que herede de la clase Collidable, y así podremos utilizar el método isColliding para comprobar si ha ocurrido una colisión entre un objeto que cae desde la parte superior de la pantalla y el jugador.
// objects.h
...
class ObJ: public Collidable{
...
Y para la definición de la clase ObJ, haremos que herede de la clase Collidable, y así podremos utilizar el método isColliding para comprobar si ha ocurrido una colisión entre un objeto que cae desde la parte superior de la pantalla y el jugador.
ObJ::ObJ(): Collidable(0,0,16,16){
this->x = 0;
this->y = 0;
this->type = NONE;
this->active = false;
}
ObJ::ObJ(byte x, byte y, ObjType type) : Collidable(x,y,16,16){
this->x = x;
this->y = y;
this->type = type;
this->active = false;
}
...
void ObJ::Update(Arduboy2Base* arduboy) {
// Actualizar la posición del objeto
...
this->setCollider(this->x,this->y,16,16);
}
Ahora ya estamos listos para comprobar si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla, utilizando el método isColliding de la clase Collidable.
Vamos a movernos a la función UpdateGamePlay del fichero arduinogame.ino, donde vamos a comprobar si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla. Si ha ocurrido una colisión, podemos restar una vida al jugador o aumentar su puntuación, dependiendo del tipo de objeto con el que haya colisionado.
void UpdateGameplay() {
...
for(int i = 0;i<MAX_OBJS;i++){
if(objs[i].isActive() && objs[i].isColliding(&arduboy,playr)){
if(objs[i].getType()==CANDY){
playr.addScore(10);
objs[i].setActive(false);
}else{
playr.decreasseLive();
objs[i].setActive(false);
if(playr.getLives()<=0){
currentState = GAME_OVER;
}
}
}
}
}
Como podemos ver en el código anterior, estamos comprobando si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla. Si ha ocurrido una colisión, comprobamos el tipo de objeto con el que ha colisionado el jugador. Si es un caramelo, aumentamos la puntuación del jugador en 10 puntos y desactivamos el objeto. Si es un obstáculo, restamos una vida al jugador y desactivamos el objeto. Si el jugador se queda sin vidas, cambiamos el estado del juego a GAME_OVER.
Una vez hemos visto estos cambios, ya podemos comprobar si ha ocurrido una colisión entre el jugador y un objeto que cae desde la parte superior de la pantalla, y aplicar la lógica correspondiente en el juego.