sábado, 10 de octubre de 2020

Control de Colisiones

Este curso continua con el programa anterior animando un personaje, y ahora vamos a añadirle el control de colisiones.

Tal y como muestra en el video, se puede ver como se mueve el personaje por el escenario chocando con los objetos de la escena.


Para el control de colisiones en este ejemplo se utiliza un mapa de choque, que se trata de un mapa pintando de rojo las zonas donde se quiere que choque el personaje.

Cuando se mueva el personaje se debe de controlar si se entra en una zona pintada de rojo, para ello se ha utilizado una función esRojo(). 

Esta funcion comprueba un punto concreto dentro de la imagen de choque, obtiene su color y comprueba si el color es rojo. 

La función para obtener un pixel de una imagen es la siguiente:

ALLEGRO_COLOR al_get_pixel(ALLEGRO_BITMAP *bitmap, int x, int y)

Esta funcion extrae de una imagen un pixel de la posicion (x,y), y devuelve un ALLEGRO_COLOR con la información de dicho pixel. Esta función es lenta y como se va a utilizar varias veces se recomienda bloquear la imagen, con el comando al_lock_bitmap.

En el ejemplo para evitar que se relentice solo se comprueba cuatro puntos de choque.

Se ha añadido una nueva clase llamada escenario, que es la que se encarga de las imagenes del escenario. 

El escenario consta de tres imágenes:

  1. suelo: contiene toda la imagen global de la escena.
  2. cielo: contiene las imágenes que irán sobre el personaje, es decir, que taparan al personaje.
  3. choque: contiene el mapa de choque del escenario, marcando en rojo la zona en la que choca.


Estas tres imagenes deben tener el mismo tamaño, para un funcionamiento correcto.


class escenario {
    ALLEGRO_BITMAP* suelo; 
    ALLEGRO_BITMAP* cielo;
    ALLEGRO_BITMAP* choque;
public:
    void carga()
    {
        suelo  = al_load_bitmap("datos/escenaN.png");
        cielo  = al_load_bitmap("datos/escenaS.png");
        choque = al_load_bitmap("datos/escenaC.png");
    }
    void pinta(bool sup = false)
    {
        if (!sup) al_draw_bitmap(suelo, 0, 0, 0);
        
        al_draw_bitmap(cielo, 0, 0, 0);
                
    }
    bool esRojo(int x, int y)
    {
        unsigned char r, g, b;
        ALLEGRO_COLOR colorMira;
        colorMira = al_get_pixel(choque, x, y);
        al_unmap_rgb(colorMira,&r, &g, &b);
        return (r == 255 && g == 0 && b == 0);
    }
} escena;


El método carga, inicializa las variables con las imágenes del escenario a mostrar.

El método pinta, se encarga de pintar las imágenes suelo y cielo. Se le puede pasar un parámetro para indicar si sup es true entonces lo que se quiere pintar es solo el cielo.

El método esRojo(), se encarga de acceder a una posición de la imagen de choque y comprobar si el pixel consultado es de color rojo, en ese caso devuelve true. 

Si está en rojo indicará que se trata de una posición bloqueada.


En la clase player, se mantiene todo igual que el anterior y se añade al método teclas lo siguiente:

- al principio se crean e inicializan dos nuevas variables ax,ay. Que se encargan de almacenar el estado anterior de x,y.

- Justo después de las condiciones de las teclas se añade un if para comprobar si colisiona, en caso afirmativo se vuelve a los valores antiguos.


Se añade un nuevo método llamado colisiona.


bool colisiona()
    {
        // comprobamos solo las esquinas
        if (escena.esRojo(x + 1, y + 30)) return true;
        if (escena.esRojo(x + 47, y + 48)) return true;
        if (escena.esRojo(x + 1, y + 48)) return true;
        if (escena.esRojo(x + 47, y + 30)) return true;
        return false;
    }


En la función dibuja se ha añadido para pintar el escenario.


void dibuja(void)
{    
    escena.pinta();
    jugador.pinta();
    escena.pinta(true);
    // muestra por pantalla
    al_flip_display();
}


Por tanto se pinta primero el fondo, luego el jugador, después la imagen cielo y finalmente se muestra por pantalla.


En la función juego(), se ha añadido escena.carga(); para cargar las imágenes del escenario antes de empezar a pintar.


Para que no tengan problema con el código, aquí tienen un enlace para que puedan descargar el código completo de este ejemplo, y todas las imágenes utilizadas.


1 comentario: