sábado, 3 de octubre de 2020

Animando un Personaje en 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 código 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 códigos.

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 librerías de allegro 5, las que se encargan de la imágenes, 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 código. 

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 animación del personaje, cuanto mayor sea mas lento será la animación.

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 función 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.h>

#include <allegro5/allegro_image.h>

#include <allegro5/allegro_ttf.h>

#include <allegro5/allegro_font.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);      

}


No hay comentarios:

Publicar un comentario

Antes de publicar un comentario

Todos los comentarios que se realicen en el blog son moderados.

Debido a esto es muy probable que tu comentario no aparezca de inmediato ya que previamente debe ser revisado para evitar un mal uso (SPAM).

Podrán realizar comentario cualquiera que tenga una cuenta de Google.

Related Posts Plugin for WordPress, Blogger...