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 función 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 función extrae de una imagen un pixel de la posición (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 debe bloquear la imagen, con el comando al_lock_bitmap.

Este comando bloquea la imagen para que se pueda acceder de una forma mas rápida, concretamente se bloquea como imagen de solo lectura.

Se ha añadido una nueva clase llamada escenario, que es la que se encarga de las imágenes 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 imágenes 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);
                
    }
    void bloquea()
    {
      lock = al_lock_bitmap(choque, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY);
    }
    void desbloquea()
    {
      al_unlock_bitmap(choque);
    }
    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.


    void bloquea()
    {
      lock = al_lock_bitmap(choque, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY);
    }
    void desbloquea()
    {
      al_unlock_bitmap(choque);
    }

Estas funciones son añadidas en la clase escenario y se utilizaran antes y al finalizar la comprobación de la colisión del personaje. 

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()
    {
        escena.bloquea();
        bool valor = false;
        for (int i = 1; i < 47; i++)
        {
            for (int j = 30; j < 48; j++)
            {
                int vx = x + i;
                int vy = y + j;
                if (escena.esRojo(vx, vy))
                {
                    valor = true;
                }
            }
        }    
        escena.desbloquea();
        return valor;
    }

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, tienen un enlace para que puedan descargar el código completo de este ejemplo, y todas las imágenes utilizadas.

Haz click aquí para Descargar Código e Imágenes.

SHARE
    Blogger Comment

0 comentarios:

Publicar un comentario