Animando personaje con C++ y Allegro 5

 



Esta es la continuación del curso Animación con allegro 5. Animando un personaje esta en C++ y se utiliza la librería Allegro 5. A continuación se muestra un video con el resultado de este curso. 


Tal y como se ve en el video se tiene un personaje que podremos mover mediante las teclas de flechas del cursor. A diferencia con el curso anterior en este ya se añade una clase player para controlar el manejo del personaje, y se incluye un fondo de escenario. El codigo aunque aun esta todo en el mismo archivo ya esta dividido para que se pueda separar según convenga, de este modo tenerlo todo mas ordenado y poder reaprovechar los codigos. A continuación se explica paso a paso todo el código del ejemplo.
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/allegro_font.h>
Lo primero de todo que se debe hacer es incluir las librerías que se van a utilizar, en este caso se incluyen las librerias de allegro 5, las que se encargan de la imgenes, y las fuentes (tipo de textos).
int desplaza = 2;
int mueve = 18;
ALLEGRO_FONT* font;
struct {
    int FPS;   
    ALLEGRO_EVENT_QUEUE* Mis_eventos;
    ALLEGRO_COLOR fondo;
    ALLEGRO_BITMAP* img;
} sistema;
Se declaran algunas variables globales para poder acceder a ellas desde cualquier parte de nuestro codigo. La variable desplaza indica el numero de pixels que se va a desplazar cuando pulsemos alguna de las teclas del manejo de nuestro personaje. La variable mueve indica el numero de frames que debes esperar para que cambie la imagen de la animacion del personaje, cuanto mayor sea mas lento será la animacion. font es utilizada para guardar el formato de la fuente que se utiliza en nuestro ejemplo. Struct crea una structura que contiene varias variables FPS para indicar los Frames Por Segundo, Mis_eventos es una lista de eventos, fondo es un color que se utilizará para borrar el fondo de la pantalla. img contiene la imagen que se muestra de fondo. Y sistema engloba toda esta estructura.
class player
{
    // posicion del personaje
    int x, y;
    int dir;
    int paso;
    int tiempoPaso;
    int tiempoCont;

    ALLEGRO_BITMAP* img;

public:

    void inicia()
    {
        img = al_load_bitmap("datos/personaje.png");
        tiempoPaso = int(sistema.FPS / mueve);
        tiempoCont = 0;
        x = 100;
        y = 50;
        dir = 0;
        paso = 0;
    }

    void teclas(ALLEGRO_EVENT evento)
    {
        ALLEGRO_KEYBOARD_STATE teclado;
    
        al_get_keyboard_state(&teclado);

        if (al_key_down(&teclado, ALLEGRO_KEY_UP))
        {
            y -= desplaza;
            dir = 3;            
            tiempoCont++;
        }
        if (al_key_down(&teclado, ALLEGRO_KEY_DOWN))
        {
            y += desplaza;
            dir = 0;
            tiempoCont++;
        }
        if (al_key_down(&teclado, ALLEGRO_KEY_LEFT))
        {
            x -= desplaza;
            dir = 1;
            tiempoCont++;
        }
        if (al_key_down(&teclado, ALLEGRO_KEY_RIGHT))
        {
            x += desplaza;
            dir = 2;
            tiempoCont++;
        }

        // limitadores
        if (x < 0) x = 0;
        if (x > 800 - 48) x = 800 - 48;
        if (y < 0) y = 0;
        if (y > 600 - 48) y = 600 - 48;
        if (tiempoCont > tiempoPaso)
        {
            paso++;
            tiempoCont = 0;
        }

        if (paso > 2) paso = 0;
    }

    void pinta()
    {
        al_draw_bitmap_region(img, paso * 48, dir * 48, 48, 48, x, y, 0);
    }

} jugador;
La clase player es la que se encarga del manejo del personaje. jugador es una variable de la clase player. player contiene varias variables privadas
 // posicion del personaje
    int x, y;
    int dir;
    int paso;
    int tiempoPaso;
    int tiempoCont;

    ALLEGRO_BITMAP* img;
    
La posición del personaje se almacena en x,y. dir contiene la direccion hacia donde mira nuestro personaje. paso indica cual de las tres imagenes se debe de mostrar. tiempoPaso y tiempoCont se utilizan para relentizar la animacion del personaje. img contiene la imagen del personaje. La clase player tiene tres métodos, player que sirve para inicializar, teclas que se encarga del control de las teclas que mueven al personaje, y pinta que se encarga de pintar en pantalla el personaje.
void dibuja(void)
{    
    al_clear_to_color(sistema.fondo);
    al_draw_bitmap(sistema.img, 0, 0, 0);
    al_draw_text(font, al_map_rgb(0, 0, 0), 50, 520, 0, "KodayRPG 2020");

    jugador.pinta();
    // muestra por pantalla
    al_flip_display();
}
La funcion dibuja se encarga de pintar todo por pantalla, primero borra su contenido con un color, luego pinta el escenario contenido en img, pinta el texto, el personaje y finalmente se muestra por pantalla.
void juego()
{
    font = al_load_ttf_font("datos/neuropol.ttf", 64, 0);
    ALLEGRO_EVENT evento;
    bool repetir = true;
    bool dibujar = true;

    jugador.inicia();

    while (repetir)
    {
        // Pinta si es dibuja y esta vacia la lista de eventos
        if (dibujar && al_event_queue_is_empty(sistema.Mis_eventos))
        {                       
            dibuja();
            dibujar = false;
        }

        // esperamos a que ocurra un evento
        al_wait_for_event(sistema.Mis_eventos, &evento);

        // se ha cerrado la ventana
        if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            repetir = false;
        }

        // se ha pulsado ESC
        if (evento.type == ALLEGRO_EVENT_KEY_DOWN)
        {
            if (evento.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
            {
                repetir = false;
            }
        }

        // pasa un tiempo determinado
        if (evento.type == ALLEGRO_EVENT_TIMER)
        {
            dibujar = true;
            jugador.teclas(evento);
        }

    }

    al_destroy_font(font);
}
la funcion juego se puede decir que es el nucleo del juego, contiene el bucle principal que se esta repitiendo hasta que se pulse ESC o se cierre la ventana. Dentro del bucle el codigo mas importante es: al_wait_for_event(sistema.Mis_eventos, &evento); Se encarga de esperar hasta que ocurra alguno de los eventos, de esta manera se controla la velocidad del juego. Los eventos posibles son: Teclado al_register_event_source(sistema.Mis_eventos, al_get_keyboard_event_source()); Pantalla al_register_event_source(sistema.Mis_eventos, al_get_display_event_source(display)); Temporizador al_register_event_source(sistema.Mis_eventos, al_get_timer_event_source(timer)); En cuanto alguno de los eventos esta activo continua la ejecución, y a continuación se comprueba con los if cada uno de los posibles casos.
        // se ha cerrado la ventana
        if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            repetir = false;
        }

        // se ha pulsado ESC
        if (evento.type == ALLEGRO_EVENT_KEY_DOWN)
        {
            if (evento.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
            {
                repetir = false;
            }
        }

        // pasa un tiempo determinado
        if (evento.type == ALLEGRO_EVENT_TIMER)
        {
            dibujar = true;
            jugador.teclas(evento);
        }
        
De este modo si se ha cerrado la ventana o pulsado ESC la variable repetir es false y se sale del bucle. Si pasó el tiempo entonces indica que se debe pintar por pantalla.
int main(void)
{
    // inicializamos las librerías utilizadas
    al_init();
    al_init_font_addon();
    al_init_ttf_addon();
    al_init_image_addon();
    al_install_keyboard();

    ALLEGRO_DISPLAY* display = al_create_display(800, 600);
    ALLEGRO_TIMER* timer = NULL;

    al_set_window_title(display, "KodayRPG");

    sistema.img = al_load_bitmap("datos/escenario.png");
    sistema.fondo = al_map_rgb(255, 255, 255);
    sistema.FPS = 60;    
    timer = al_create_timer(1.0 / sistema.FPS);

    // creo lista de eventos
    sistema.Mis_eventos = al_create_event_queue();

    // asigno eventos a la lista de eventos
    al_register_event_source(sistema.Mis_eventos, al_get_keyboard_event_source());
    al_register_event_source(sistema.Mis_eventos, al_get_display_event_source(display));
    al_register_event_source(sistema.Mis_eventos, al_get_timer_event_source(timer));
    al_start_timer(timer);

    juego();

    al_destroy_display(display);      
}
En el main lo primero que se debe hacer antes de utilizar la librería Allegro es inicializar la libreria. A continuación se crea display para indicar la resolucion de nuestra aplicación. Se inicializa las variables de sistema, que contiene la imagen de fondo, el color, los FPS. Y se crea la lista de eventos que se desea controlar. Bueno y a continuación teneis todo el código completo que debe ir en el archivo main.cpp
/*
  _  __              _                   _____    _____     _____ 
 | |/ /             | |                 |  __ \  |  __ \   / ____|
 | ' /    ___     __| |   __ _   _   _  | |__) | | |__) | | |  __ 
 |  <    / _ \   / _` |  / _` | | | | | |  _  /  |  ___/  | | |_ |
 | . \  | (_) | | (_| | | (_| | | |_| | | | \ \  | |      | |__| |
 |_|\_\  \___/   \__,_|  \__,_|  \__, | |_|  \_\ |_|       \_____|
                                  __/ |                           
                                 |___/                            

BLOG : https://programacion-cpp.blogspot.com/
WEB  : https://devcpp-allegro.blogspot.com/                                 
*/

#include <allegro5/allegro_font.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_ttf.h>

int desplaza = 2;
int mueve = 18;
ALLEGRO_FONT* font;

struct {
    int FPS;   
    ALLEGRO_EVENT_QUEUE* Mis_eventos;
    ALLEGRO_COLOR fondo;
    ALLEGRO_BITMAP* img;
} sistema;

class player
{
    // posicion del personaje
    int x, y;
    int dir;
    int paso;
    int tiempoPaso;
    int tiempoCont;

    ALLEGRO_BITMAP* img;

public:

    void inicia()
    {
        img = al_load_bitmap("datos/personaje.png");
        tiempoPaso = int(sistema.FPS / mueve);
        tiempoCont = 0;
        x = 100;
        y = 50;
        dir = 0;
        paso = 0;
    }

    void teclas(ALLEGRO_EVENT evento)
    {
        ALLEGRO_KEYBOARD_STATE teclado;
    
        al_get_keyboard_state(&teclado);

        if (al_key_down(&teclado, ALLEGRO_KEY_UP))
        {
            y -= desplaza;
            dir = 3;            
            tiempoCont++;
        }
        if (al_key_down(&teclado, ALLEGRO_KEY_DOWN))
        {
            y += desplaza;
            dir = 0;
            tiempoCont++;
        }
        if (al_key_down(&teclado, ALLEGRO_KEY_LEFT))
        {
            x -= desplaza;
            dir = 1;
            tiempoCont++;
        }
        if (al_key_down(&teclado, ALLEGRO_KEY_RIGHT))
        {
            x += desplaza;
            dir = 2;
            tiempoCont++;
        }

        // limitadores
        if (x < 0) x = 0;
        if (x > 800 - 48) x = 800 - 48;
        if (y < 0) y = 0;
        if (y > 600 - 48) y = 600 - 48;
        if (tiempoCont > tiempoPaso)
        {
            paso++;
            tiempoCont = 0;
        }

        if (paso > 2) paso = 0;
    }

    void pinta()
    {
        al_draw_bitmap_region(img, paso * 48, dir * 48, 48, 48, x, y, 0);
    }

} jugador;


void dibuja(void)
{    
    al_clear_to_color(sistema.fondo);
    al_draw_bitmap(sistema.img, 0, 0, 0);
    al_draw_text(font, al_map_rgb(0, 0, 0), 50, 520, 0, "KodayRPG 2020");

    jugador.pinta();
    // muestra por pantalla
    al_flip_display();
}

void juego()
{
    font = al_load_ttf_font("datos/neuropol.ttf", 64, 0);
    ALLEGRO_EVENT evento;
    bool repetir = true;
    bool dibujar = true;

    jugador.inicia();

    while (repetir)
    {
        // Pinta si es dibuja y esta vacia la lista de eventos
        if (dibujar && al_event_queue_is_empty(sistema.Mis_eventos))
        {                       
            dibuja();
            dibujar = false;
        }

        // esperamos a que ocurra un evento
        al_wait_for_event(sistema.Mis_eventos, &evento);

        // se ha cerrado la ventana
        if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            repetir = false;
        }

        // se ha pulsado ESC
        if (evento.type == ALLEGRO_EVENT_KEY_DOWN)
        {
            if (evento.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
            {
                repetir = false;
            }
        }

        // pasa un tiempo determinado
        if (evento.type == ALLEGRO_EVENT_TIMER)
        {
            dibujar = true;
            jugador.teclas(evento);
        }

    }

    al_destroy_font(font);
}


int main(void)
{
    // inicializamos las librerías utilizadas
    al_init();
    al_init_font_addon();
    al_init_ttf_addon();
    al_init_image_addon();
    al_install_keyboard();

    ALLEGRO_DISPLAY* display = al_create_display(800, 600);
    ALLEGRO_TIMER* timer = NULL;

    al_set_window_title(display, "KodayRPG");

    sistema.img = al_load_bitmap("datos/escenario.png");
    sistema.fondo = al_map_rgb(255, 255, 255);
    sistema.FPS = 60;    
    timer = al_create_timer(1.0 / sistema.FPS);

    // creo lista de eventos
    sistema.Mis_eventos = al_create_event_queue();

    // asigno eventos a la lista de eventos
    al_register_event_source(sistema.Mis_eventos, al_get_keyboard_event_source());
    al_register_event_source(sistema.Mis_eventos, al_get_display_event_source(display));
    al_register_event_source(sistema.Mis_eventos, al_get_timer_event_source(timer));
    al_start_timer(timer);

    juego();

    al_destroy_display(display);      
}

A continuación tenéis las imágenes utilizadas en el ejemplo.




SHARE
    Blogger Comment

0 comentarios:

Publicar un comentario