O allegro 5 introduziu o uso de eventos. Eventos são coisa que acontecem no programa desde cliques e movimentos do mouse, teclas serem pressionadas, um temporizador disparou, dentre outras coisas.
Caso o allegro não tivesse suporte a eventos, teríamos que verificar quando cada uma destas coisas acontecessem no programa em determinados espaços de tempo, e esta tarefa deixaria é demandante para o processador.
Para lidar com eventos, usamos uma fila de eventos. Cada vez que um evento acontece, ele é colocado na fila. Então quando o programa verificar se existe algum evento a ser tratado, removemos da fila o evento mais antigo e tratamos ele.
No exemplo abaixo, iremos criar um evento que permite tratar o que acontece ao clicar no botão X que fecha a janela. Analisemos o código:
// Os arquivos de cabeçalho #include <allegro5/allegro.h> #include <allegro5/allegro_native_dialog.h> #include <allegro5/allegro_image.h> // Atributos da tela #define LARGURA_TELA 640 #define ALTURA_TELA 480 void error_msg(char *text){ al_show_native_message_box(NULL,"ERRO", "Ocorreu o seguinte erro e o programa sera finalizado:", text,NULL,ALLEGRO_MESSAGEBOX_ERROR); } int main(void){ ALLEGRO_DISPLAY *janela = NULL; ALLEGRO_BITMAP *imagem = NULL; //declara a fila de eventos ALLEGRO_EVENT_QUEUE *fila_eventos = NULL; //Inicialização da biblioteca Allegro if (!al_init()){ error_msg("Falha ao inicializar a Allegro"); return -1; } //tenta iniciar o módulo de imagens if (!al_init_image_addon()){ error_msg("Falha ao inicializar add-on allegro_image"); return -1; } //cria display em janela janela = al_create_display(LARGURA_TELA, ALTURA_TELA); //caso al_create_display retorne NULL, encerra programa if (!janela){ error_msg("Falha ao criar janela"); return -1; } //carrega imagem imagem = al_load_bitmap("hu3.bmp"); //caso al_load_bitmap retorne NULL, encerra programa if (!imagem){ error_msg("Falha ao carregar o arquivo de imagem"); al_destroy_display(janela); return -1; } //cria fila de eventos fila_eventos = al_create_event_queue(); //caso al_create_event_queue retorne NULL, destroi a janela e encerra o programa if (!fila_eventos){ error_msg("Falha ao criar fila de eventos"); al_destroy_display(janela); return -1; } //registra eventos da janela em fila_eventos al_register_event_source(fila_eventos, al_get_display_event_source(janela)); //desenha imagem no display ativo em X:0 Y:0 al_draw_bitmap(imagem, 0, 0, 0); //atualiza tela al_flip_display(); while (1){ //declara vriavel que recebe evento e timeout ALLEGRO_EVENT evento; //espero por um evento da fila, e guarda em evento al_wait_for_event(fila_eventos, &evento); //se teve eventos e foi um evento de fechar janela, encerra repetição if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { int resp = al_show_native_message_box(janela,"Fechar", "Deseja sair do programa?","",NULL,ALLEGRO_MESSAGEBOX_YES_NO); if (resp) break; } al_draw_bitmap(imagem, 0, 0, 0); al_flip_display(); } //destroi janela e fila de eventos ao fim al_destroy_display(janela); al_destroy_event_queue(fila_eventos); return 0; }
Na linha 20 criamos a variável que será usada como a fila de eventos, explicada anteriormente. Toda vez que um evento for disparado, ele será guardado nesta fila. E toda vez que quisermos remover um evento da fila (para resolver ele), sempre será removido o evento que está aguardando a mais tempo, como numa fila de pessoas esperando por atendimento.
Na linha 52 chamamos a função al_create_event_queue(), que cria uma fila de eventos vazia. A fila é atribuída á variável fila_eventos. Em caso de falha retorna NULL. O caso de falha está sendo verificado na linha 54.
51-61
Na linha 61 chamamos a função al_register_event_source() que serve para ligar uma fonte de eventos à fila de eventos criada. Sem isto, por mais que os eventos ocorressem, o programa não iria colocá-los na fila. A função recebe por parâmetro a fila de eventos e a fonte dos eventos. Como queremos que a nossa fonte de eventos seja a janela, então chamamos a função al_get_display_event_source(), que retorna a fonte de eventos da janela passada por parâmetro.
A seguir desenhamos a imagem na janela (linha 64) e atualizamos a tela (linha 67).
69-85
O while acima é onde futuramente ficará toda lógica dos jogos que criaremos. Todo jogo se baseia em atualizar a tela em um intervalo de tempo predeterminado (idealmente 60 vezes por segundo, ou 60 fps), além de capturar entrada do usuário (por teclado, mouse, ou outros) e executar a lógica específica do jogo. Este processo acontece repetidamente até que o jogo termine. Neste nosso tutorial que trata de eventos, iremos utilizar o while para ficar "escutando" o evento do clique do X da janela.
Na linha 71 criamos uma variável que irá guardar um evento. Basicamente pegaremos um evento da fila (quando um estiver disponível) e colocamos ele na variável evento. As variáveis ALLEGRO_EVENT são structs, cujo campo type indica o tipo de evento que foi disparado. Consulte a referência para a lista completa de tipos de eventos possíveis.
Na linha 73 chamamos a função al_wait_for_event(), que remove o primeiro item da fila de eventos e coloca na variável evento.
Na linha 76 verificamos se o tipo do evento (campo type da variável ALLEGRO_EVENT) disparado foi ALLEGRO_EVENT_DISPLAY_CLOSE. Em caso afirmativo, significa que o usuário clicou no botão para fechar a janela.
Na linha 77 mostramos uma mensagem perguntando se o usuário deseja fechar o programa. Caso o botão Sim seja clicando, o break na linha 80 fará com que o while encerre.
Ao fim do programa, nas linhas 88 e 89, os espaços de memória para a janela e fila de eventos são liberados.