Tutorial Allegro 5 #5 – Utilizando o Mouse

Padrão

Olá, leitores!

Hoje vamos começar a falar sobre como manipular as entradas em nossos jogos. Neste post, veremos como tratar os eventos do mouse e como utilizá-los em nossa aplicação. Pra quem já conheceu a versão anterior da Allegro, verá que com a sua estruturação em eventos, ficou muito mais organizado obter as entradas.

Vamos ao código de nossa aplicação e em seguida discutiremos o que tem de novo nele. A aplicação consiste em um retângulo centralizado na tela e um pequeno retângulo vermelho no canto inferior direito da tela. Se o ponteiro do mouse estiver sobre este retângulo central, ele fica verde. Senão, fica branco. E ao clicar sobre o retângulo vermelho, a aplicação é encerrada.

// Os arquivos de cabeçalho<br />
#include &lt;allegro5/allegro.h&gt;</p>
<p>#include &lt;stdio.h&gt;</p>
<p>// Atributos da tela<br />
const int LARGURA_TELA = 640;<br />
const int ALTURA_TELA = 480;</p>
<p>int main(void)<br />
{<br />
    ALLEGRO_DISPLAY *janela = NULL;<br />
    ALLEGRO_EVENT_QUEUE *fila_eventos = NULL;<br />
    ALLEGRO_BITMAP *botao_sair = NULL, *area_central = 0;<br />
    // Flag que condicionará nosso looping<br />
    int sair = 0;</p>
<p>    if (!al_init())<br />
    {<br />
        fprintf(stderr, &quot;Falha ao inicializar a Allegro.\n&quot;);<br />
        return -1;<br />
    }</p>
<p>    janela = al_create_display(LARGURA_TELA, ALTURA_TELA);<br />
    if (!janela)<br />
    {<br />
        fprintf(stderr, &quot;Falha ao criar janela.\n&quot;);<br />
        return -1;<br />
    }</p>
<p>    // Configura o título da janela<br />
    al_set_window_title(janela, &quot;Rotinas de Mouse - www.rafaeltoledo.net&quot;);</p>
<p>    // Torna apto o uso de mouse na aplicação<br />
    if (!al_install_mouse())<br />
    {<br />
        fprintf(stderr, &quot;Falha ao inicializar o mouse.\n&quot;);<br />
        al_destroy_display(janela);<br />
        return -1;<br />
    }</p>
<p>    // Atribui o cursor padrão do sistema para ser usado<br />
    if (!al_set_system_mouse_cursor(janela, ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT))<br />
    {<br />
        fprintf(stderr, &quot;Falha ao atribuir ponteiro do mouse.\n&quot;);<br />
        al_destroy_display(janela);<br />
        return -1;<br />
    }</p>
<p>    // Alocamos o retângulo central da tela<br />
    area_central = al_create_bitmap(LARGURA_TELA / 2, ALTURA_TELA / 2);<br />
    if (!area_central)<br />
    {<br />
        fprintf(stderr, &quot;Falha ao criar bitmap.\n&quot;);<br />
        al_destroy_display(janela);<br />
        return -1;<br />
    }</p>
<p>    // Alocamos o botão para fechar a aplicação<br />
    botao_sair = al_create_bitmap(100, 50);<br />
    if (!botao_sair)<br />
    {<br />
        fprintf(stderr, &quot;Falha ao criar botão de saída.\n&quot;);<br />
        al_destroy_bitmap(area_central);<br />
        al_destroy_display(janela);<br />
        return -1;<br />
    }</p>
<p>    fila_eventos = al_create_event_queue();<br />
    if (!fila_eventos)<br />
    {<br />
        fprintf(stderr, &quot;Falha ao inicializar o fila de eventos.\n&quot;);<br />
        al_destroy_display(janela);<br />
        return -1;<br />
    }</p>
<p>    // Dizemos que vamos tratar os eventos vindos do mouse<br />
    al_register_event_source(fila_eventos, al_get_mouse_event_source());</p>
<p>    // Flag indicando se o mouse está sobre o retângulo central<br />
    int na_area_central = 0;<br />
    while (!sair)<br />
    {<br />
        // Verificamos se há eventos na fila<br />
        while (!al_is_event_queue_empty(fila_eventos))<br />
        {<br />
            ALLEGRO_EVENT evento;<br />
            al_wait_for_event(fila_eventos, &amp;evento);</p>
<p>            // Se o evento foi de movimentação do mouse<br />
            if (evento.type == ALLEGRO_EVENT_MOUSE_AXES)<br />
            {<br />
                // Verificamos se ele está sobre a região do retângulo central<br />
                if (evento.mouse.x &gt;= LARGURA_TELA / 2 - al_get_bitmap_width(area_central) / 2 &amp;&amp;<br />
                    evento.mouse.x &lt;= LARGURA_TELA / 2 + al_get_bitmap_width(area_central) / 2 &amp;&amp;<br />
                    evento.mouse.y &gt;= ALTURA_TELA / 2 - al_get_bitmap_height(area_central) / 2 &amp;&amp;<br />
                    evento.mouse.y &lt;= ALTURA_TELA / 2 + al_get_bitmap_height(area_central) / 2)<br />
                {<br />
                    na_area_central = 1;<br />
                }<br />
                else<br />
                {<br />
                    na_area_central = 0;<br />
                }<br />
            }<br />
            // Ou se o evento foi um clique do mouse<br />
            else if (evento.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)<br />
            {<br />
                if (evento.mouse.x &gt;= LARGURA_TELA - al_get_bitmap_width(botao_sair) - 10 &amp;&amp;<br />
                    evento.mouse.x &lt;= LARGURA_TELA - 10 &amp;&amp; evento.mouse.y &lt;= ALTURA_TELA - 10 &amp;&amp;<br />
                    evento.mouse.y &gt;= ALTURA_TELA - al_get_bitmap_height(botao_sair) - 10)<br />
                {<br />
                    sair = 1;<br />
                }<br />
            }<br />
        }</p>
<p>        // Limpamos a tela<br />
        al_clear_to_color(al_map_rgb(0, 0, 0));</p>
<p>        // Colorimos o bitmap correspondente ao retângulo central,<br />
        // com a cor condicionada ao conteúdo da flag na_area_central<br />
        al_set_target_bitmap(area_central);<br />
        if (!na_area_central)<br />
        {<br />
            al_clear_to_color(al_map_rgb(255, 255, 255));<br />
        }<br />
        else<br />
        {<br />
            al_clear_to_color(al_map_rgb(0, 255, 0));<br />
        }</p>
<p>        // Colorimos o bitmap do botão de sair<br />
        al_set_target_bitmap(botao_sair);<br />
        al_clear_to_color(al_map_rgb(255, 0, 0));</p>
<p>        // Desenhamos os retângulos na tela<br />
        al_set_target_bitmap(al_get_backbuffer(janela));<br />
        al_draw_bitmap(area_central, LARGURA_TELA / 2 - al_get_bitmap_width(area_central) / 2,<br />
                       ALTURA_TELA / 2 - al_get_bitmap_height(area_central) / 2, 0);<br />
        al_draw_bitmap(botao_sair, LARGURA_TELA - al_get_bitmap_width(botao_sair) - 10,<br />
                       ALTURA_TELA - al_get_bitmap_height(botao_sair) - 10, 0);</p>
<p>        // Atualiza a tela<br />
        al_flip_display();<br />
    }</p>
<p>    // Desaloca os recursos utilizados na aplicação<br />
    al_destroy_bitmap(botao_sair);<br />
    al_destroy_bitmap(area_central);<br />
    al_destroy_display(janela);<br />
    al_destroy_event_queue(fila_eventos);</p>
<p>    return 0;<br />
}<br />

Bom, vocês podem perceber que temos vários elementos novos neste código. Vamos passo a passo descrevendo o funcionamento de cada coisa. Inicialmente, dentro da função main() temos a declaração da tela e dois bitmaps que representarão os dois retângulos que teremos em nossa janela. Além disso, temos uma variável chamada sair que será a condição para sair do looping principal. Na parte de inicializações, temos o comando para configurar o título da janela. Como já foi dito anteriormente, a Allegro 5 tem suporte a várias janelas. Assim, precisamos especificar na função al_set_window_title() a janela que receberá a alteração e qual o nome que desejamos configurar. Mais à frente, na linha 35, temos a inicialização do mouse. Com a chamada à função al_install_mouse() dizemos ao nosso aplicativo para relevar os dados vindos do mouse. Em seguida, fazemos uma chamada à função al_set_system_mouse_cursor(), atribuindo um dos ponteiros padrão do sistema. Passamos como argumento a janela que vamos utilizar o ponteiro e qual ponteiro utilizar. No exemplo utilizamos o cursor padrão do sistema, através da constante ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT, mas é possível configurar qualquer outro (aqui você tem a lista de constantes). Em seguida, nas linhas 51 e 60 criamos os dois bitmaps referentes aos dois retângulos que farão parte da nossa janela, através da função al_create_bitmap() que recebe, respectivamente, a largura e a altura do bitmap em pixels. Em seguida criamos a nossa fila de eventos e, na linha 78, dizemos que vamos tratar os eventos originados no mouse (já havíamos visto como registrar os eventos da janela no tutorial 3). Em seguida temos o nosso looping principal, condicionado à variável sair. Dentro do looping, verificamos se a fila de eventos não está vazia, através da função al_is_event_queue_empty(). Caso haja eventos, retiramos o primeiro evento e verificamos se ele é originário do movimento do mouse (ALLEGRO_EVENT_MOUSE_AXES) ou do clique do botão, que nesse caso eu tratei como o movimento de soltar o botão (ALLEGRO_EVENT_MOUSE_BUTTON_UP), evitando uma sobrecarga de eventos caso o usuário mantenha o botão pressionado.

Caso o evento seja de movimento, verificamos o posicionamento do mouse em relação ao retângulo central. Como sabemos que desenhamos o retângulo de maneira centralizada, comparamos utilizando as características da tela e do quadrado. Cabe destacar que o evento nos fornece uma série de dados, como por exemplo, a posição do mouse no momento em que o evento ocorreu. No exemplo, acessamos as coordenadas através de evento.mouse.x e evento.mouse.y. Outro ponto importante são as funções para obter-se o tamanho de um bitmap. A função al_get_bitmap_width() retorna a largura do bitmap passado como parâmetro e a função al_get_bitmap_height() nos retorna a sua altura, ambos os valores em pixels. Em nossa lógica, caso o ponteiro do mouse esteja dentro do retângulo central, atribuímos um valor à variável. Já se o evento seja um clique do mouse, verificamos se o clique foi dentro da área que corresponde ao retângulo vermelho. Caso positivo, atribuímos o valor à flag de saída.

Completando o looping, temos o trecho de código que se encarrega de atualizar a tela. Primeiramente “apagamos” o conteúdo da tela, pintando-a de preto. Após isso, modificamos o nosso bitmap de destino para a área central, chamando a função al_set_target_bitmap(). Lembra que eu comentei que a Allegro funcionava como uma máquina de estados? Então, é através disso que a modificamos para o bitmap de destino que desejamos. Após a troca, colorimos o retângulo de acordo com o conteúdo da flag. Em seguida mudamos para o bitmap que representa o botão de sair e o colorimos de vermelho. No final voltamos à tela (para acessar o bitmap correspondente à tela, precisamos chamar a função al_get_backbuffer()) e aplicamos os dois retângulos a ela.

Por fim, fora do looping, encerramos a aplicação desalocando os bitmaps e destruindo a tela e a fila de eventos. E pronto!

Para compilar, basta linkar com o núcleo da Allegro:

  • Windows: -lallegro-5.0.4-mt
  • Linux: -lallegro

Como podem ter percebido, a complexidade dos nossos aplicativos estão aumentando gradativamente. Mas podem ficar tranquilo que não deve ficar muito “pior” que isso daqui pra frente 😉

Só uma notícia: saiu a versão 5.0.5 da Allegro (podem baixar aqui). Então, a partir dos próximos posts, vou compilar utilizando essa versão nova. Na verdade, é só modificar o a versão na hora de colocar a configuração do linker. Nada mais que isso.

Bom pessoal, é isso! Até a próxima! 😀