Aprendendo Allegro 5
Início Janela Imagens Mensagem Fontes e texto Eventos Mouse Teclado Audio Timer Animações Sprites Jogo exemplo

Utilizando a entrada do mouse

Neste tutorial iremos aprender a como utlilizar o mouse em nossos programas. A captura do movimento e cliques do mouse é feita através dos eventos, aprendidos na lição anterior. Neste exemplos iremos criar duas áreas coloridas, onde uma reagirá com o movimento do mouse, e a outra ao clique do mouse. Vamos ao código:

// Os arquivos de cabeçalho
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.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_EVENT_QUEUE *fila_eventos = NULL;
    ALLEGRO_BITMAP *botao_sair = NULL, *area_central = 0;
    // Flag que condicionará nosso looping
    int sair = 0;

    if (!al_init()){
        error_msg("Falha ao inicializar a Allegro");
        return -1;
    }

    janela = al_create_display(LARGURA_TELA, ALTURA_TELA);
    if (!janela){
        error_msg("Falha ao criar janela");
        return -1;
    }

    // Configura o título da janela
    al_set_window_title(janela, "Rotinas de Mouse");

    // Torna apto o uso de mouse na aplicação
    if (!al_install_mouse()){
        error_msg("Falha ao inicializar o mouse");
        al_destroy_display(janela);
        return -1;
    }

    // Atribui o cursor padrão do sistema para ser usado
    if (!al_set_system_mouse_cursor(janela, ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT)){
        error_msg("Falha ao atribuir ponteiro do mouse");
        al_destroy_display(janela);
        return -1;
    }

    // Alocamos o retângulo central da tela
    area_central = al_create_bitmap(LARGURA_TELA / 2, ALTURA_TELA / 2);
    if (!area_central){
        error_msg("Falha ao criar bitmap");
        al_destroy_display(janela);
        return -1;
    }

    // Alocamos o botão para fechar a aplicação
    botao_sair = al_create_bitmap(100, 50);
    if (!botao_sair){
        error_msg("Falha ao criar botão de saída");
        al_destroy_bitmap(area_central);
        al_destroy_display(janela);
        return -1;
    }

    fila_eventos = al_create_event_queue();
    if (!fila_eventos){
        error_msg("Falha ao inicializar o fila de eventos");
        al_destroy_display(janela);
        return -1;
    }

    // Dizemos que vamos tratar os eventos vindos do mouse
    al_register_event_source(fila_eventos, al_get_mouse_event_source());

    // Flag indicando se o mouse está sobre o retângulo central
    int na_area_central = 0;
    while (!sair){
        // Verificamos se há eventos na fila
        while (!al_is_event_queue_empty(fila_eventos)){
            ALLEGRO_EVENT evento;
            al_wait_for_event(fila_eventos, &evento);

            // Se o evento foi de movimentação do mouse
            if (evento.type == ALLEGRO_EVENT_MOUSE_AXES){
                // Verificamos se ele está sobre a região do retângulo central
                if (evento.mouse.x >= LARGURA_TELA / 2 - al_get_bitmap_width(area_central) / 2 &&
                evento.mouse.x <= LARGURA_TELA / 2 + al_get_bitmap_width(area_central) / 2 &&
                evento.mouse.y >= ALTURA_TELA / 2 - al_get_bitmap_height(area_central) / 2 &&
                evento.mouse.y <= ALTURA_TELA / 2 + al_get_bitmap_height(area_central) / 2){
                    na_area_central = 1;
                }
                else{
                    na_area_central = 0;
                }
            }
            // Ou se o evento foi um clique do mouse
            else if (evento.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP){
                if (evento.mouse.x >= LARGURA_TELA - al_get_bitmap_width(botao_sair) - 10 &&
                evento.mouse.x <= LARGURA_TELA - 10 && evento.mouse.y <= ALTURA_TELA - 10 &&
                evento.mouse.y >= ALTURA_TELA - al_get_bitmap_height(botao_sair) - 10){
                    sair = 1;
                }
            }
        }

        // Limpamos a tela
        al_clear_to_color(al_map_rgb(0, 0, 0));

        // Colorimos o bitmap correspondente ao retângulo central,
        // com a cor condicionada ao conteúdo da flag na_area_central
        al_set_target_bitmap(area_central);
        if (!na_area_central){
            al_clear_to_color(al_map_rgb(255, 255, 255));
        }
        else{
            al_clear_to_color(al_map_rgb(0, 255, 0));
        }

        // Colorimos o bitmap do botão de sair
        al_set_target_bitmap(botao_sair);
        al_clear_to_color(al_map_rgb(255, 0, 0));

        // Desenhamos os retângulos na tela
        al_set_target_bitmap(al_get_backbuffer(janela));
        al_draw_bitmap(area_central, LARGURA_TELA / 2 - al_get_bitmap_width(area_central) / 2,
        ALTURA_TELA / 2 - al_get_bitmap_height(area_central) / 2, 0);
        al_draw_bitmap(botao_sair, LARGURA_TELA - al_get_bitmap_width(botao_sair) - 10,
        ALTURA_TELA - al_get_bitmap_height(botao_sair) - 10, 0);

        // Atualiza a tela
        al_flip_display();
    }

    // Desaloca os recursos utilizados na aplicação
    al_destroy_bitmap(botao_sair);
    al_destroy_bitmap(area_central);
    al_destroy_display(janela);
    al_destroy_event_queue(fila_eventos);

    return 0;
}

No início do programa declaramos algumas variáveis, e iniciamos a biblioteca e addons. Tudo isso já foi visto anteriormente. Vamos direto ao que temos de novo.

al_set_window_title()

Na linha 34 chamamos a função al_set_window_title(), que muda o texto da janela. Ela recebe o display, e a string contendo o texto.

al_install_mouse()

Na linha 37 chamamos a função al_install_mouse(), permite o uso dos eventos relativos à captura de cliques e movimentos do mouse.

al_set_system_mouse_cursor()

Na linha 44 chamamos a função al_install_mouse(), que que serve para definir o tipo de cursor do mouse que será usado em uma determinada janela. Ela recebe como parâmetro o display, e uma flag indicando o tipo de cursor. No exemplo, usamos ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT, que é o cursor padrão. Consulte a referência para conhecer os outros tipos de cursores disponíveis.

al_create_bitmap()

Na linha 51 e linha 59 usamos a função al_create_bitmap(), que cria uma área gráfica, chamada bitmap, nas posições X e Y informadas por parâmetro. Já havíamos trabalhado com a função al_load_bitmap(), que carrega uma imagem em um bitmap. A diferença é que al_create_bitmap() cria a área sem atribuir nada a ela, somente com as dimensões especificadas.

al_get_mouse_event_source()

Note que nas linhas seguintes criamos a fila de eventos (explicada anteriormente) e inicamos a mesma. Na linha 75 porém, usamos como segundo parâmetro de al_register_event_source() (função que faz com que a fila de eventos guarde os eventos de uma determinada fonte de eventos) o retorno da função al_get_mouse_event_source(). Isto faz com que todos eventos relacionados ao mouse sejam registrados na fila de eventos. Diferente desta, lembre-se que na lição anterior havíamos registrado os eventos da janela na fila.

Lógica do problema

Os seguintes passos serão executados, até que a flag sair==0:

  1. Enquanto tiver eventos na fila:
    1. Verifica-se se o cursor do mouse está sobre o bitmap central. Se sim seta a flag na_area_central=1;
    2. Verifica-se se o clique do mouse foi feito sobre o bitmap menor. Se sim, seta a flag sair=1;
  2. Colore os dois bitmaps;
  3. Desenha um deles no centro da janela, e o outro no canto inferior direito;
  4. Atualiza a tela.

Na linha 78 criamos a flag na_area_central que começa em 0, e irá receber 1 quando o mouse estiver sobre o bitmap do centro da janela.

al_is_event_queue_empty()

Na linha 81 usamos a função al_is_event_queue_empty que verifica se a fila de eventos passada por parâmetro está vazia. Como nossa while está condicionado à esta função, este trecho de código só deixará de ser executado quando todos os eventos tiverem sido tratados.

al_wait_for_event()

Neste exemplo, usamos a função al_wait_for_event() na linha 83, que difere da função al_wait_for_event_until() já utilizada porque ela não recebe o timeout como último parâmetro. Isto quer dizer que o programa fica esperando até que o evento aconteça.

Na linha 86 testamos se o tipo do evento disparado é ALLEGRO_EVENT_MOUSE_AXES, que representa o movimento do mouse.

al_get_bitmap_width() e al_get_bitmap_height()

O if das linhas 88 à 91 testa se o ponteiro do mouse está entre as dimensões do bitmap maior, nas coordenadas X e Y. a função al_get_bitmap_width() serve para pegar a largura do bitmap e al_get_bitmap_height() a altura. Os campos mouse.x e mouse.y da variável ALLEGRO_EVENT acessam as posições X e Y do ponteiro do mouse, relativos à janela.

Na linha 99 testamos se o tipo do evento disparado é ALLEGRO_EVENT_MOUSE_BUTTON_UP, que representa o botão do mouse sendo soltado. Caso seja do desejo testar qual botão foi pressionado, usamos o campo mouse.button que possuirá os valores 1, 2 ou 3 para os botões esquerdo, direito e central, respectivamente. O if testa testa se o usuário ao clicar na janela, o cursor está dentro do espaço do bitmap menor. E em caso afirmativo seta a flag sair=1.

al_set_target_bitmap()

Após sair da repetição que verifica os eventos, na linha 113 chamamos a função al_set_target_bitmap() que muda o bitmap ativo para o bitmap area_central. Lembrando que as funções que fazem alterações em bitmaps (mudança de cor, desenho, etc) levam consideração sempre o bitmap ativo (por padrão o último display criado). Como já colorimos a janela com a cor preta na linha 109 e agora queremos colorir o bitmap area_central, devemos mudar o bitmap ativo. Por isso chamamos a função al_set_target_bitmap(). Em seguida colorimos ele na cor branca (R:255 G:255 B:255) ou na cor verde (R:0 G:255 B:0), dependendo do valor da flag na_area_central (que depende da posição do cursor do mouse, conforme vimos acima, na linha 92). Em seguida o mesmo é feito com o outro bitmap, o botao_sair.

al_get_backbuffer()

Na linha 126 queremos devolver o bitmap ativo para a janela, pois chegou o momento de escrever a area_central e botao_sair nela. Então chamamos a função al_set_target_bitmap(), mas ao invés de usar a janela como parâmetro, chamamos a função al_get_backbuffer(). E o porque disso será explicado.

Existem duas áreas de desenho da tela: O front buffer, e o back buffer. Quando criamos o display, automaticamente ele se torna o display ativo (isso já sabemos), e todas rotinas de desenho são feitas no back buffer desse display. O que está no front buffer é o que é mostrado na tela. Pontanto, ao usar a função al_flip_display(), o conteúdo do front e back buffer se inverte, fazendo com que mostremos o que antes estava no back buffer, por isso chamamos essa função de "função que atualiza a tela".

Com isso, percebemos que o bitmat ativo (aquele que desenhamos em cima) nunca deve ser o front buffer do display. Por conta disso, que quando mudamos o bitmap ativo de volta para a janela, precisamos mudar para o back buffer da janela, daí entra a função al_get_backbuffer().

Daí em diante no código é simples, desenhamos os dois bitmaps em posições diferentes da janela (no back buffer dela), e atualizamos a tela (trocando o front com o back buffer).

Outros links