Ir ao conteúdo
  • Cadastre-se

Sprites usando Allegro no C


Posts recomendados

Oi, pessoal. Comecei a fazer um jogo point&click, que achei que seria um bom começo pra aprender a usar o Allegro. Quando o usuário clicasse na margem esquerda ou direita da tela, iria pra tela seguinte (como seria esperado). Entretanto, quando fui implementar uma seta pra indicar isso pro usuário, o background fica piscando. Tentei usar a função al_set_target_bitmap() pro background, mas o programa fecha na hora.

 

Como faço então pra carregar um sprite sobre um background?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@vangodp tô usando o allegro 5.0 no DevC++.

Sobre o código, não tem nada muito complicado (o que me faz questionar porque não dá certo).

void CarregarBackground(ALLEGRO_BITMAP *background, char NomeDoBackground[], ALLEGRO_DISPLAY_MODE disp_data)
{
  	 //já tinha testado essa função antes, somente carregando e alternando backgrounds, e tava funcionando do jeito esperado
     background = al_load_bitmap(NomeDoBackground);
     al_draw_scaled_bitmap(background,0,0,XBKG,YBKG,0,0,disp_data.width,disp_data.height,0);	//XBKG e YBKG são macros definindo o tamanho do arquivo de background, pra ampliar do tamanho certo
     al_flip_display();
     al_destroy_bitmap(background);	//Isso realmente soa muito estranho, mas se eu não destruísse o background imediatamente, ele não desocupava a memória, e com algumas mudanças de tela já travava tudo
}

void DesenharSeta(ALLEGRO_BITMAP *seta, ALLEGRO_DISPLAY_MODE disp_data)
{
     al_draw_bitmap(seta, (disp_data.width)/2, (disp_data.height)/2, 0);
     al_flip_display();
     al_destroy_bitmap(seta);
}

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Iury Benites
1 - Não se destrói um bitmap a não ser que você tenha certeza de que não irá mais utiliza-lo.

 

2 - Quando você tem uma função pra carregar algum bitmap, nunca coloque um comando que descarrega o bitmap dentro dessa função "al_destroy_bitmap(background);". Toda vez que você chama a função para carregar o bitmap ele carregava, desenhava e depois destruía.

 

3 -  O problema do crescimento de memória ocorre porque você está colocando a função de carregar o bitmap em loop, só necessita carregar o bitmap 1 vez, em loop você coloca as funções de limpar a tela e desenhar os bitmaps na tela novamente.

 

4 - Separe suas funções:

--  "Carregar todas as bitmaps que você vai utilizar no jogo todo(1 vez)"

--  "desenhar bitmaps na tela(em loop)"

--  "destruir bitmaps da memória(1 vez no final do programa ou ao sair)".

5 - Poste o código completo, assim da pra te ajudar melhor.


Espero ter ajudado, bons estudos...

  • Curtir 3
Link para o comentário
Compartilhar em outros sites

@CiroboyBR sim, faz bastante sentido, na verdade. O problema é que me baseei num tutorial que ensinava simplesmente a desenhar uma imagem e deu, e daí tentei expandir (a base de muita gambiarra, admito :v). Encontrava pouca coisa sobre allegro 5, muito menos bem explicado.

Acredito que isso resolva tudo. Assim que eu implementar, eu posto aqui.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Ok, separei as funções entre "Carregar Background", "Exibir Background" e "Destruir Background". O problema é na hora de exibir. Essa demo que estou fazendo se trata de quatro backgrounds, como se fossem as paredes de uma sala. Quando o usuário coloca o cursor na margem esquerda ou direita, e clica, vai para a tela correspondente (e isso dá certo tranquilo).
O problema é na hora de exibir uma seta para o usuário, indicando que ele está na posição correta. Segue o código:

void DesenharSala(ALLEGRO_BITMAP *background1, ALLEGRO_BITMAP *background2, ALLEGRO_BITMAP *background3, ALLEGRO_BITMAP *background4, int numero, ALLEGRO_DISPLAY_MODE disp_data)
{
     if(numero == 0)
               al_draw_scaled_bitmap(background1,0,0,XBKG,YBKG,0,0,disp_data.width,disp_data.height,0);
     else
     if(numero == 1)
               al_draw_scaled_bitmap(background2,0,0,XBKG,YBKG,0,0,disp_data.width,disp_data.height,0);
     else
     if(numero == 2)
               al_draw_scaled_bitmap(background3,0,0,XBKG,YBKG,0,0,disp_data.width,disp_data.height,0);
     else
         al_draw_scaled_bitmap(background4,0,0,XBKG,YBKG,0,0,disp_data.width,disp_data.height,0);
}

void DesenharSeta(ALLEGRO_BITMAP *seta, ALLEGRO_DISPLAY_MODE disp_data, int lugar)
{
     if(lugar == DIREITA)
              al_draw_bitmap(seta, disp_data.width - 130, disp_data.height / 2, ALLEGRO_FLIP_HORIZONTAL);
     else
         al_draw_bitmap(seta, 0, disp_data.height / 2, 0);
}

O problema parece ser onde colocar a função "al_flip_display()". Se coloco antes da seta, ela não aparece, se coloco depois, o background some e fica só a seta.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

pense nesses elementos como se fosse na vida real. você está desenhando em um buffer todas essas imagens, se for fazer uma analogia o buffer seria a mesa de trabalho, na qual colocamos fotos em cima. O background seria a primeira imagem a por sobre a mesa(buffer) pois ela fica no fundo, logo colocaríamos a seta acima do fundo, pense como se fossem capas do fotoshop. A ordem correta é desenhar o fundo e posteriormente a seta, e por ultimo mostrar com o flip, essa seria a ordem correta.

Posso lhe deixar um código feito as pressas:
 

#include <allegro5/allegro.h> // Librería inicial de Allegro
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h> // Addon de primitivas (figuras)
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_native_dialog.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
#define VENTANA_X 800
#define VENTANA_Y 600
#define DIREITA 1


// Funciones
void inicializar ( ALLEGRO_DISPLAY **display ) {
    // Inicializar los addons
    if ( !al_init() ) {
        fprintf ( stderr, "Error al inicializar Allegro." ); // Imprimir errores en stream STDERR
        exit ( -1 );
    }

    //Inicializando capacidade para manejo de imagenes
//    if ( !al_init_image_addon() ) {
//        al_show_native_message_box ( *display, "Error", "Error", "Failed to initialize al_init_image_addon!", NULL, ALLEGRO_MESSAGEBOX_ERROR );
//        //return 0;
//        exit ( -1 );
//    }    
    
    //Inicializando capacidade para manejo de primitivas
    if ( !al_init_primitives_addon() ) {
        fprintf ( stderr, "Error al inicializar el addon de primitivas." ); // Imprimir errores en stream STDERR
        exit ( -2 );
    }
    

    *display = al_create_display ( VENTANA_X, VENTANA_Y ); // Crear el display de tamaño 500x300 píxeles
    
    al_set_window_title ( *display, "Ejemplo Allegro 5 - www.multiaportes.com" ); // Establecer el título de la ventana
}

void finalizar ( ALLEGRO_DISPLAY **display ) {
    al_shutdown_primitives_addon(); // Finalizar el addon de primitivas
    al_destroy_display ( *display ); // Destruir la ventana
}


void DesenharEscena ( ALLEGRO_BITMAP *background[4], int indice ) {

}

void DesenharSeta ( ALLEGRO_BITMAP *seta, ALLEGRO_DISPLAY_MODE disp_data, int dst ) {
    if ( dst == DIREITA )
        al_draw_bitmap ( seta, disp_data.width - 130, disp_data.height / 2, ALLEGRO_FLIP_HORIZONTAL );
    else
        al_draw_bitmap ( seta, 0, disp_data.height / 2, 0 );
}

int main ( void ) {
    

/* Our window. */
ALLEGRO_DISPLAY *display = NULL;
/* Our tiles atlas. */
//ALLEGRO_BITMAP *tiles;
/* Our tilemap. */
//int tile_map[100 * 100];
/* Keep track of pressed mouse button. */
int mouse;
/* Camera parameters. */
float zoom = 1.0, rotate;
float scroll_x, scroll_y;
/* Our icon font and background. */
ALLEGRO_BITMAP *icon;
ALLEGRO_FONT *font;
ALLEGRO_BITMAP  *image[5] = {0};    
/* Simple FPS counter. */
int fps, fps_accum;
double fps_time;
/*cola de eventos*/    
ALLEGRO_EVENT_QUEUE *queue;
/*Usaremos para gestionar el tiempo. */
ALLEGRO_TIMER *timer;
/*usaremos para redeseñar la pagina. */
bool redraw = true;
    
    //srand(time(NULL));

    /* Init Allegro 5 + addons. */
    al_init();
    al_init_image_addon();
    al_init_primitives_addon();
    al_init_font_addon();
    al_install_mouse();
    al_install_keyboard();
    
    inicializar ( &display );

    
    
    char path[100];
    for ( int i=0; i < 4 ; i++ ) {
        sprintf(path, "imagen/img%d.png", i);
        image[i] = al_load_bitmap ( path );
        if ( image[i] == NULL ) {
            al_show_native_message_box ( display, "Error", "Error", "Falhou ao carregar as imagens!", NULL, ALLEGRO_MESSAGEBOX_ERROR );
            al_destroy_display ( display );
            return 0;
        }    
    }
    
    

    
    /* The example will work without those, but there will be no
     * FPS display and no icon.
     */
    
    
   font = al_load_font("imagen/fixed_font.tga", 0, 0);
   if (!font) {
      printf("imagen/fixed_font.tga not found.\n");
      exit(-7);
   } 
    
    icon = al_load_bitmap("image/icon.tga");
    printf("%d", icon);
    if (icon) al_set_display_icon(display, icon);

    timer = al_create_timer(1.0 / 60);
    queue = al_create_event_queue();
    al_register_event_source(queue, al_get_keyboard_event_source());
    al_register_event_source(queue, al_get_mouse_event_source());
    al_register_event_source(queue, al_get_display_event_source(display));
    al_register_event_source(queue, al_get_timer_event_source(timer));
    al_start_timer(timer);

    while (1) {
        ALLEGRO_EVENT event;
        al_wait_for_event(queue, &event);

        if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
            break;
        if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
            if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                break;
        }
        if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
            mouse = event.mouse.button;
        }
        if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
            mouse = 0;
        }
        if (event.type == ALLEGRO_EVENT_MOUSE_AXES) {
            //Left button scrolls.
            if (mouse == 1) {
                float x = event.mouse.dx / zoom;
                float y = event.mouse.dy / zoom;
                scroll_x -= x * cos(rotate) + y * sin(rotate);
                scroll_y -= y * cos(rotate) - x * sin(rotate);
            }
            //Right button zooms/rotates.
            if (mouse == 2) {
                rotate += event.mouse.dx * 0.01;
                zoom += event.mouse.dy * 0.01 * zoom;
            }
            zoom += event.mouse.dz * 0.1 * zoom;
            if (zoom < 0.1) zoom = 0.1;
            if (zoom > 10) zoom = 10;

        }
        if (event.type == ALLEGRO_EVENT_TIMER) redraw = true;
        if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) {
            al_acknowledge_resize(display);
            redraw = true;
        }

        if (redraw && al_is_event_queue_empty(queue)) {
            redraw = false;
            double t = al_get_time();
            
            //draw here
            //tile_map_draw();
            al_draw_bitmap(image[0],0,0,0);
            al_draw_bitmap(image[3],600,300,0);
            
            if (font) {
                al_draw_filled_rounded_rectangle(4, 4, 100, 30, 8, 8, al_map_rgba(255, 0, 0, 0));
                al_draw_textf(font, al_map_rgb(255, 0, 0), 54, 8, ALLEGRO_ALIGN_CENTRE, "FPS: %d", fps);
            }
            al_flip_display();
            fps_accum++;
            if (t - fps_time >= 1) {
                fps = fps_accum;
                fps_accum = 0;
                fps_time = t;
            }
        }
    }    

    for (int i=0; i<4 ; i++) {
        al_destroy_bitmap ( image[i] );
    }
    
    
    finalizar ( &display );
    return 0;
}

Não lhe servirá mais que como exemplo para ilustrar a ideia. Tem muita coisa errada nesse código mas também tem muitas idéias interessantes. Por exemplo podemos carregar imagens por lotes e seria possivel desenhar da mesma forma automatizando tudo.

Um dos grandes erros que tem esse programa é o seguinte. Pense que você tem que carregar 4 imagens, você teria que fazer algo como:
ALLEGRO_BITMAP  *image1 = al_load_bitmap ( "img1.png" );
ALLEGRO_BITMAP  *image2 = al_load_bitmap ( "img2.png" );
....
e assim por diante com cada uma delas. Qual o problema disso? Pois imagine que você teve sorte ao carregar 3 imagens, e justo na ultima o programa não encontra a 4ª imagem.... Que acontece? Consegue ver o erro?  Pois que se você usou return para sair do programa você criou um buraco na memória, pois você saiu sem liberar as 3 primeiras imagens pois a função al_load_bitmap () reserva memória dinamicamente e lhe retorna um ponteiro, e ja sabemos que tudo o que for dinâmico tem que ser liberado antes de sair, si não você tem um bonito vazamento de memória. Pois bem a coisa n4ao termina aí... imagina que depois de carregar 3 mil imagens e 500 musicas falha na hora da carga de uma fonte, se você acha que é só fazer um return você ta enganado, melhor seria você apagar o pc hahahaha. você precisa fazer um inventario de tudo o que foi carregado na memória de forma correta para ser liberado em caso de falho, e também em caso de sair do programa.

em fim... se quiser o projeto completo para codeblocks para dar uma olhada é só dizer >_<

fui

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@vangodp Lendo teu comentário em voz alta eu percebi meu erro (bem simples de resolver, inclusive). Na função que chamava a próxima tela (se o cursor estava numa das margens e clicava com o botão esquerdo), desenhava a imagem e já chamava al_flip_display(). Então quando eu desenhava a seta e usava al_flip_display(), ficava só a seta (erro de principiante, suponho).

Sobre o código que tu postou, vou aproveitar com certeza o uso de vetores (considerando que todas as salas sempre terão 4 lados, posso usar um vetor estático sem problemas). Eu tinha tentado antes, mas esqueci que é um vetor de ponteiros.
Acho que agora tenho o que é preciso pra terminar o jogo (mas antes, dar uma boa "limpa" no código, que tá cheio de coisas que não preciso mais)

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...