Tutorial Allegro 5 #14 – Entrada de Texto

Padrão

Olá pessoal! Depois de algum tempo sem os posts da série sobre Allegro, estamos de volta! No exemplo de hoje, vamos ver como obter uma entrada de texto do usuário, já que nativamente não temos uma forma de obter um texto (como um scanf ou cin).

Neste exemplo, vamos simular que você terminou um jogo e fez a melhor pontuação e então precisará digitar seu nome para ir para o ranking. No aplicativo, em vez de utilizarmos o evento ALLEGRO_EVENT_KEY_DOWN, usaremos ALLEGRO_EVENT_KEY_CHAR para obtermos os caracteres relativos a cada uma das teclas. Vamos olhar o código e em seguida comentamos seus detalhes. Lembrando que este exemplo foi baseado do lazyfoo.net, com a diferença de que aqui estamos utilizando Allegro 5 em vez de SDL, e adaptei-o para C em vez de C++.

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

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

const int LARGURA_TELA = 640;
const int ALTURA_TELA = 480;

ALLEGRO_BITMAP *fundo = NULL;
ALLEGRO_DISPLAY *janela = NULL;
ALLEGRO_FONT *fonte = NULL;
ALLEGRO_EVENT_QUEUE *fila_eventos = NULL;

char str[17];

void manipular_entrada(ALLEGRO_EVENT evento);
void exibir_texto_centralizado();

bool inicializar();
bool carregar_arquivos();
void finalizar();

int main(void)
{
    bool sair = false;
    bool concluido = false;

    if (!inicializar())
    {
        return -1;
    }

    strcpy(str, "");

    if (!carregar_arquivos())
    {
        return -1;
    }

    while (!sair)
    {
        while (!al_is_event_queue_empty(fila_eventos))
        {
            ALLEGRO_EVENT evento;
            al_wait_for_event(fila_eventos, &evento);

            if (!concluido)
            {
                manipular_entrada(evento);

                if (evento.type == ALLEGRO_EVENT_KEY_DOWN && evento.keyboard.keycode == ALLEGRO_KEY_ENTER)
                {
                    concluido = true;
                }
            }

            if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
            {
                sair = true;
            }
        }

        al_draw_bitmap(fundo, 0, 0, 0);

        if (!concluido)
        {
            al_draw_text(fonte, al_map_rgb(255, 255, 255), LARGURA_TELA / 2,
                        (ALTURA_TELA / 2 - al_get_font_ascent(fonte)) / 2,
                        ALLEGRO_ALIGN_CENTRE, "Melhor Pontuação! Nome:");
        }
        else
        {
            al_draw_text(fonte, al_map_rgb(255, 255, 255), LARGURA_TELA / 2,
                        (ALTURA_TELA / 2 - al_get_font_ascent(fonte)) / 2,
                        ALLEGRO_ALIGN_CENTRE, "1º Lugar");
        }

        exibir_texto_centralizado();

        al_flip_display();
    }

    finalizar();

    return 0;
}

bool inicializar()
{
    if (!al_init())
    {
        fprintf(stderr, "Falha ao inicializar a biblioteca Allegro.\n");
        return false;
    }

    if (!al_install_keyboard())
    {
        fprintf(stderr, "Falha ao inicializar teclado.\n");
        return false;
    }

    if (!al_init_image_addon())
    {
        fprintf(stderr, "Falha ao inicializar allegro_image.\n");
        return false;
    }

    al_init_font_addon();

    if (!al_init_ttf_addon())
    {
        fprintf(stderr, "Falha ao inicializar allegro_ttf.\n");
        return false;
    }

    janela = al_create_display(LARGURA_TELA, ALTURA_TELA);
    if (!janela)
    {
        fprintf(stderr, "Falha ao criar a janela.\n");
        return false;
    }

    fila_eventos = al_create_event_queue();
    if (!fila_eventos)
    {
        fprintf(stderr, "Falha ao criar fila de eventos.\n");
        return false;
    }

    al_set_window_title(janela, "Entrada de Texto");

    al_register_event_source(fila_eventos, al_get_display_event_source(janela));
    al_register_event_source(fila_eventos, al_get_keyboard_event_source());

    return true;
}

bool carregar_arquivos()
{
    fundo = al_load_bitmap("bg.jpg");
    if (!fundo)
    {
        fprintf(stderr, "Falha ao carregar \"bg.jpg\".\n");
        return false;
    }

    fonte = al_load_font("comic.ttf", 42, 0);
    if (!fonte)
    {
        fprintf(stderr, "Falha ao carregar \"comic.ttf\".\n");
        return false;
    }

    return true;
}

void finalizar()
{
    al_destroy_bitmap(fundo);
    al_destroy_font(fonte);
    al_destroy_event_queue(fila_eventos);
    al_destroy_display(janela);
}

void manipular_entrada(ALLEGRO_EVENT evento)
{
    if (evento.type == ALLEGRO_EVENT_KEY_CHAR)
    {
        if (strlen(str) <= 16)
        {
            char temp[] = {evento.keyboard.unichar, '\0'};
            if (evento.keyboard.unichar == ' ')
            {
                strcat(str, temp);
            }
            else if (evento.keyboard.unichar >= '0' &&
                     evento.keyboard.unichar <= '9')
            {
                strcat(str, temp);
            }
            else if (evento.keyboard.unichar >= 'A' &&
                     evento.keyboard.unichar <= 'Z')
            {
                strcat(str, temp);
            }
            else if (evento.keyboard.unichar >= 'a' &&
                     evento.keyboard.unichar <= 'z')
            {
                strcat(str, temp);
            }
        }

        if (evento.keyboard.keycode == ALLEGRO_KEY_BACKSPACE && strlen(str) != 0)
        {
            str[strlen(str) - 1] = '\0';
        }
    }
}

void exibir_texto_centralizado()
{
    if (strlen(str) > 0)
    {
        al_draw_text(fonte, al_map_rgb(255, 255, 255), LARGURA_TELA / 2,
                     (ALTURA_TELA - al_get_font_ascent(fonte)) / 2,
                     ALLEGRO_ALIGN_CENTRE, str);
    }
}

No nosso exemplo, os itens chave são a string str e a função manipular_entrada(). A string, de 17 posições (16 caracteres + caratere indicando fim de string), é inicializada na linha 37, dentro da função main(). Ainda na função main(), temos uma flag chamada concluido, que indicará quando o usuário pressionar a tecla Enter, encerrando a digitação do nome.

Dentro do trecho de tratamento de eventos, temos a chamada à função manipular_entrada(), que passando o evento como parâmetro. Internamente, nessa função, verificamos o campo keyboard.unichar do evento, caso ele seja do tipo ALLEGRO_EVENT_KEY_CHAR. Este campo contém o caractere correspondente a tecla pressionada. Primeiramente, montamos uma string temporária na linha 175 que, caso possua um valor dentro do esperado (números ou caracteres (maiúsculos ou minúsculos)), será concatenada a string str por meio da função strcat(). Como em C o tipo char pode ser tratado como int, utilizamos os comparadores >= e <= para validar a faixa dos valores. Caso estejam, eles são adicionados à string principal str. Ainda na função manipular_entrada(), verificamos se a tecla pressionada foi a backspace, para então remover o último caractere da string str na linha 199.

Voltando à função main(), temos uma verificação da flag concluido para escolher entre qual mensagem será exibida ao usuário: “Melhor Pontuação! Nome:” ou “1º Lugar”. No final do looping temos a chamada a função exibir_texto_centralizado(), mas não temos nenhuma novidade em sua implementação.

O aplicativo rodando deve parecer com isso:

A imagem e a fonte, você pode usar qualquer uma a seu gosto, bastando alterar na função carregar_arquivos(). Para compilar, utilizamos os add-ons allegro_image, allegro_font e allegro_ttf.

  • Windows: -lallegro-5.0.5-mt -lallegro_image-5.0.5-mt -lallegro_font-5.0.5-mt -lallegro_ttf-5.0.5-mt
  • Linux: -lallegro -lallegro_image -lallegro_font -lallegro_ttf

Bom, é isso pessoal! Espero que o tutorial seja útil! Acredito que no ponto que estamos, já seja possível começar a fazer alguns jogos. Criatividade pessoal! 🙂

  • AGP

    Como faço para arrumar a acentuação? Sempre quando utilizo acento o texto é apresentado deformado. Ótimos tutoriais, ajudou muito!

  • Davi Rodrigues

    VERI GUDI

    Muito obrigado, me salvou no desenvolvimento de um trabalho sobre um aplicativo no meu curso de Lógica de Programação…

    Thank you very much!