Ir ao conteúdo
  • Cadastre-se

C++ Allegro5 colisão entre retangulos


GGuilioti

Posts recomendados

Bom, estou estudando c++ em casa e sei apenas o básico, comecei desenvolver um jogo com a API Allegro 5, porém eu travei em uma parte.

Eu criei uma matriz que funciona como meu mapa, um Enum para identificar os tipos de chãos do meu mapa, quando na matriz for 0 é água, e etc. Quando for o número 2, no mapa é desenhado uma pedra e essa pedra não poderia ser ultrapassada por isso coloquei um sistema de colisão que quando o personagem encosta no tile da pedra as variaveis do movimento ficam falsas e assim ele pare de andar, o problema é que depois de ficar false a colisão ainda continua true por isso não consigo andar novamente, como sou iniciante estou com problemas nessa parte, alguém teria alguma dica pra me ajudar?

 

Array do mapa

int map[10][10] =  {0,0,1,1,1,1,1,1,0,0,
                        0,0,1,1,1,2,1,1,1,1,
                        0,0,0,0,0,1,1,0,0,1};

 

Desenho do mapa e colisão se for pedra

Vale ressaltar que se cima,baixo,esquerda e direita se foram verdadeiros alteram o valor da variavel a e b fazendo com que o mapa se mexa o personagem permaneça no centro da tela. BlockSize é o tamanho de cada quadrado ou tile da tela. px e py é o primeiro ponto do quadrado do personagem.

 

 

for(int i=0; i < 10; i++)
        {
         for(int j=0; j < 10; j++)
                if(map[j] == 0)
                {
                    al_draw_bitmap(agua,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                } else if(map[j] == 1)
                {
                    al_draw_bitmap(grama,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                }else if(map[j] == 2)
                {
                    al_draw_bitmap(pedra,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                    if (colisao(px, py, 32, 32, (j* BlockSize) + a, (i*BlockSize+ b), 32, 32) == true)
                    {
                        cima = false;
                        baixo = false;
                        esquerda = false;
                        direita = false;
                    }
                }
        }

Função da colisão

 

bool colisao(float ax, float ay, float acomp, float aalt, float bx, float by, float bcomp, float balt)
{
    if (ay+aalt < by) return false;
        else if(ay > by+balt) return false;
        else if(ax+acomp < bx) return false;
        else if(ax > bx+bcomp) return false;


        return true;
}

 

 

Link para o comentário
Compartilhar em outros sites

1 minuto atrás, CiroboyBR disse:

@GGuilioti Você não tem uma função ou parte do código onde controla a direção? Exemplo, se você apertar pra cima, a variável cima deve receber o valor verdadeiro.

então, essa parte existe o problema é que quando ocorre a colisao ela passa a ser true e fica pra sempre, entao os valores de andar acabam ficando false pra sempre também, o que eu pretendia era fazer a colisão ficar true somente em um instante porém não sei nem por onde começar, outra coisa seria quando eles colidirem o personagem receber as cordenadas do tile anterior à colisão porém isso é outra coisa que não sei fazer, no mais acho que vou me aprofundar mais na linguagem para ver se consigo uma solução

Link para o comentário
Compartilhar em outros sites

9 minutos atrás, CiroboyBR disse:

@GGuilioti  Teoricamente, usar o teclado (cima, alterando a direção "cima = true"), resolveria o problema, tem algo errado no código que pode nem estar nesse trecho que você mostrou

ignore as variaveis uc,ub,ud,ue e desenhar que fazem parte da animação. O código pro mapa se mover é esse

 if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
        {
            if(ev.keyboard.keycode == ALLEGRO_KEY_UP)
            {
                cima = true;
                desenhar +=1;
                uc= false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_DOWN)
            {
                baixo = true;
                desenhar +=2;
                ub= false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT)
            {
                esquerda = true;
                desenhar +=3;
                ue= false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT)
            {
                direita = true;
                desenhar +=4;
                ud= false;
            }
        } else if (ev.type == ALLEGRO_EVENT_KEY_UP)
        {
            if(ev.keyboard.keycode == ALLEGRO_KEY_UP)
            {
                cima = false;
                desenhar = 0;
                uc= true;
                ub = false;
                ue = false;
                ud = false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_DOWN)
            {
                baixo = false;
                desenhar = 0;
                uc= false;
                ub = true;
                ue = false;
                ud = false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT)
            {
                esquerda = false;
                desenhar = 0;
                uc= false;
                ub = false;
                ue = true;
                ud = false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT)
            {
                direita = false;
                desenhar = 0;
                uc= false;
                ub = false;
                ue = false;
                ud = true;
            }
        }

 Quando a tecla é pressionada ele anda 32 pixels pra direção e quando a tecla é solta ele para de andar, o problema é que a função da colisao está fazendo com que eles fiquem false pra sempre assim nao consigo retomar o movimento

Link para o comentário
Compartilhar em outros sites

14 minutos atrás, CiroboyBR disse:

Não tem como postar o código completo?

eu achei que seria muito complexo pois eu comento pouco e é bem bagunçado kkkkkkk mas enfim posso sim

#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/events.h>
#include <allegro5/keyboard.h>
#include <allegro5/allegro_image.h>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>

#define width 800
#define height 600

#define BlockSize 32

//FUNÇÕES


bool colisao(float ax, float ay, float acomp, float aalt, float bx, float by, float bcomp, float balt)
{
    if (ay+aalt < by) return false;
        else if(ay > by+balt) return false;
        else if(ax+acomp < bx) return false;
        else if(ax > bx+bcomp) return false;


        return true;
}

enum Blocos{
agua = 0,
terra =1,
pedra =2};

int main()
{
    int map[10][10] =  {0,0,1,1,1,1,1,1,0,0,
                        0,0,1,1,1,2,1,1,1,1,
                        0,0,0,0,0,1,1,0,0,1};

    bool done = false;

    bool direita = false;
    bool esquerda = false;
    bool cima = false;
    bool baixo = false;


    float a = 0;
    float b =0;

    int desenhar = 0;

    bool uc= false;
    bool ub= false;
    bool ud= false;
    bool ue= false;

    float px = 375;
    float py = 275;
    float palt = 32;
    float pcomp = 32;


    int fps=60;

    //OBJETOS
    ALLEGRO_DISPLAY* display;
    ALLEGRO_FONT *fonte = NULL;
    ALLEGRO_EVENT_QUEUE *event_queue = NULL;
    ALLEGRO_TIMER *timer = NULL;
    ALLEGRO_BITMAP *personagem = NULL;
    ALLEGRO_BITMAP *background = NULL;
    ALLEGRO_BITMAP *icone = NULL;
    ALLEGRO_BITMAP *galoc = NULL;
    ALLEGRO_BITMAP *galod = NULL;
    ALLEGRO_BITMAP *galob = NULL;
    ALLEGRO_BITMAP *galoe = NULL;
    ALLEGRO_BITMAP *agua = NULL;
    ALLEGRO_BITMAP *grama = NULL;
    ALLEGRO_BITMAP *pedra = NULL;

    //Allegro Setup Error Message
    if(!al_init())
        return -1;

    //Screen Resolution
    display = al_create_display(width,height);


    // ADDONS
    al_init_primitives_addon();
    al_init_font_addon();
    al_init_ttf_addon();
    al_install_keyboard();
    al_install_mouse();
    timer = al_create_timer(1.0 / fps);
    al_init_image_addon();


    //Allegro Screen Creating Error
    if(!display)
        return-1;

    // SOURCES
    event_queue = al_create_event_queue();
    al_register_event_source(event_queue, al_get_keyboard_event_source());
    al_register_event_source(event_queue, al_get_display_event_source(display));
    al_register_event_source(event_queue, al_get_mouse_event_source());
    fonte = al_load_font("fonte.ttf",20 ,0);
    al_register_event_source(event_queue,al_get_timer_event_source(timer));
    personagem = al_load_bitmap("perso1.png");
    background = al_load_bitmap("background.png");
    icone = al_load_bitmap("icone.png");
    galoc = al_load_bitmap("galoc.png");
    galod = al_load_bitmap("galod.png");
    galob = al_load_bitmap("galob.png");
    galoe = al_load_bitmap("galoe.png");
    agua = al_load_bitmap("agua.png");
    grama = al_load_bitmap("grama.png");
    pedra = al_load_bitmap("pedra.png");

    al_set_window_title(display,"Physis");
    al_set_display_icon(display,icone);

    // ESCONDE O CURSOR / al_hide_mouse_cursor(display);

    al_start_timer(timer);

    while(!done)
    {
    ALLEGRO_EVENT ev;
    al_wait_for_event(event_queue, &ev);

    //FECHA COM O X
        if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
        {
            done = true;
        }

    //ANDA OU NAO
        if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
        {
            if(ev.keyboard.keycode == ALLEGRO_KEY_UP)
            {
                cima = true;
                desenhar +=1;
                uc= false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_DOWN)
            {
                baixo = true;
                desenhar +=2;
                ub= false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT)
            {
                esquerda = true;
                desenhar +=3;
                ue= false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT)
            {
                direita = true;
                desenhar +=4;
                ud= false;
            }
        } else if (ev.type == ALLEGRO_EVENT_KEY_UP)
        {
            if(ev.keyboard.keycode == ALLEGRO_KEY_UP)
            {
                cima = false;
                desenhar = 0;
                uc= true;
                ub = false;
                ue = false;
                ud = false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_DOWN)
            {
                baixo = false;
                desenhar = 0;
                uc= false;
                ub = true;
                ue = false;
                ud = false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_LEFT)
            {
                esquerda = false;
                desenhar = 0;
                uc= false;
                ub = false;
                ue = true;
                ud = false;
            }
            else if (ev.keyboard.keycode == ALLEGRO_KEY_RIGHT)
            {
                direita = false;
                desenhar = 0;
                uc= false;
                ub = false;
                ue = false;
                ud = true;
            }
        }
    //MOUSE

    //CLICA COM O BOTÃO
    /*else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
    {
        if(ev.mouse.button & 1) // & 1 - ESQUERDO, & 2 - DIREITO, & 3 - SCROLL

    }
    // SOLTA O BOTÃO
    else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
    {
    }*/

        else if(ev.type == ALLEGRO_EVENT_TIMER)
        {
                if(cima == true)
            {
                b += 32;
                ud = false;
                ue= false;
                uc = true;
                ub =false;
            } else if(baixo == true)
            {
                b -=32;
                ud = false;
                ue= false;
                uc = false;
                ub =true;
            } else if(esquerda == true)
            {
                a +=32;
                uc = false;
                ub =false;
                ud = false;
                ue= true;
            } else if(direita == true)
            {
                a -=32;
                uc = false;
                ub =false;
                ud = true;
                ue= false;
            }
        }
    for(int i=0; i < 10; i++)
        {
         for(int j=0; j < 10; j++)
                if(map[i][j] == 0)
                {
                    al_draw_bitmap(agua,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                } else if(map[i][j] == 1)
                {
                    al_draw_bitmap(grama,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                }else if(map[i][j] == 2)
                {
                    al_draw_bitmap(pedra,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                    if (colisao(px, py, 32, 32, (j* BlockSize) + a, (i*BlockSize+ b), 32, 32) == true)
                    {
                        cima = false;
                        baixo = false;
                        esquerda = false;
                        direita = false;
                    }
                }
        }
     //al_clear_to_color(al_map_rgb(255, 255, 255));

     //al_draw_bitmap(background,a,b,0);

     switch(desenhar)
        {
        case 1:
            al_draw_bitmap(personagem,375,275,0);
            break;
        case 2:
            al_draw_bitmap(personagem,375,275,0);
            break;
        case 3:
            al_draw_bitmap(personagem,375,275,0);
            break;
        case 4:
            al_draw_bitmap(personagem,375,275,0);
            break;
        default:
            if(uc == true)
        {
            al_draw_bitmap(personagem,375,275,0);
        } else if(ub == true)
        {
            al_draw_bitmap(personagem,375,275,0);
        } else if(ue == true)
        {
           al_draw_bitmap(personagem,375,275,0);
        } else if(ud == true)
        {
            al_draw_bitmap(personagem,375,275,0);
        }
            break;
        }

    //al_draw_bitmap(gb,375,275,0);
     //al_draw_filled_rectangle(playerx,playery,playerx + 50,playery +50,al_map_rgb(0,0,0));
    // circulo al_draw_filled_circle(width/2 + altera_x,height/2 + altera_y,30,al_map_rgb(0,0,0));
    // texto al_draw_text(fonte,al_map_rgb(0,0,0), width/2 , height/2 +100, ALLEGRO_ALIGN_CENTER, "is suffocating");
    //DrawMap(map);

    al_flip_display();
    al_clear_to_color(al_map_rgb(255, 255, 255));

    }
        al_destroy_display(display);
        al_destroy_font(fonte);
        al_destroy_event_queue(event_queue);
        al_destroy_timer(timer);

    return 0;
}

 

Link para o comentário
Compartilhar em outros sites

4 horas atrás, GGuilioti disse:

é bem bagunçado

E como é.

A Allegro5 não ajuda nada com esses inputs do teclado por evento, ficou bem mais complexo do que na Allegro4.

Enfim, eu testei aqui e uma possível solução seria não deixar que as variáveis de posição permaneçam  colidindo.
 

if (colisao(px, py, 32, 32, (j* BlockSize) + a, (i*BlockSize+ b), 32, 32) == true)
{ 
  a -= 32;
  b -= 32;
}

Mas você vai ter que criar as condições para colisão em cima, baixo, esquerda e direita.

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

Pra colidir com o mapa não precisa de função de bounding box (a função colisão), mas precisa apenas saber onde o mapa está e também o tamanho do tile (célula do mapa).

 

Por exemplo, você pode criar uma função getTileAt (int x, int y) que retorna um int do mapa onde o x e y são coordenadas dentro ou fora do mapa.

Você tem de verificar quando o x e y está fora ou dentro do mapa, se está dentro, retorna o int (tile) na posição coluna=x / tilesize e linha=y / tilesize.

 

Veja um exemplo comum de getTileAt:
 

class TileMap
{
  int map[100][100];//um mapa de no máximo 100x100 tiles de largura por altura
  int w, h;//largura w por altura h, menor que 100 e maior que 0
  int tilesize;
  ...//outros códigos
  //NOTA: aqui, recebe coordenadas relativa ao mundo
  int getTileAt ( int x, int y )
  {
    //agora converte as coordenas do mundo em coordenadas do mapa
    x = x / tilesize;
    y = y / tilesize;
    
    //verifica se está fora do mapa
    if (x < 0 || y < 0 || x >= w || y >= h)
      return 0;//zero é sem tile ou vazio
    //retorna a linha e coluna (céluna) do mapa
    return map[y][x];
  }
};

Dai por exemplo, se quiser verificar se o player colidiu com um objeto sólido faça algo assim:

if (tilemap.getTileAt(rectPlayer.x, rectPlayer.y + rectPlayer.h) == 1 || tilemap.getTileAt(rectPlayer.x + rectPlayer.w, rectPlayer.y + rectPlayer.h) == 1)

  colidiu com tile sólido de valor 1

tilemap é o objeto do tipo TileMap

rectPlayer é o retangulo do corpo do player, x/y posilção x e y no mundo, w/h largura/altura do rect do player

 

Observe que, com essa única função no TileMap, você pode implementar colisão estilo plataforma. Não vou entrar nesses detalhes porque isso envolveria uma explicação bem longa, mas você pode estudar esse código aqui da minha engine:

https://github.com/algunsnerds/chora_engine/blob/master/platform/tilemap.cpp

 

É uma engine bem simples, fiz ela apenas como meio de aprender melhor programação. Essa classe ai que uso, você pode ver a outra no mesmo repo chamada Entity que implementa colisão estilo super mario bros. É bem útil pra estudar.

Link para o comentário
Compartilhar em outros sites

Em 24/06/2019 às 00:14, CiroboyBR disse:

E como é.

A Allegro5 não ajuda nada com esses inputs do teclado por evento, ficou bem mais complexo do que na Allegro4.

Enfim, eu testei aqui e uma possível solução seria não deixar que as variáveis de posição permaneçam  colidindo.
 


if (colisao(px, py, 32, 32, (j* BlockSize) + a, (i*BlockSize+ b), 32, 32) == true)
{ 
  a -= 32;
  b -= 32;
}

Mas você vai ter que criar as condições para colisão em cima, baixo, esquerda e direita.

obrigado pela ajuda vou ver o que consigo fazer

 

adicionado 0 minutos depois
Em 24/06/2019 às 18:47, cpusam disse:

Pra colidir com o mapa não precisa de função de bounding box (a função colisão), mas precisa apenas saber onde o mapa está e também o tamanho do tile (célula do mapa).

 

Por exemplo, você pode criar uma função getTileAt (int x, int y) que retorna um int do mapa onde o x e y são coordenadas dentro ou fora do mapa.

Você tem de verificar quando o x e y está fora ou dentro do mapa, se está dentro, retorna o int (tile) na posição coluna=x / tilesize e linha=y / tilesize.

 

Veja um exemplo comum de getTileAt:
 


class TileMap
{
  int map[100][100];//um mapa de no máximo 100x100 tiles de largura por altura
  int w, h;//largura w por altura h, menor que 100 e maior que 0
  int tilesize;
  ...//outros códigos
  //NOTA: aqui, recebe coordenadas relativa ao mundo
  int getTileAt ( int x, int y )
  {
    //agora converte as coordenas do mundo em coordenadas do mapa
    x = x / tilesize;
    y = y / tilesize;
    
    //verifica se está fora do mapa
    if (x < 0 || y < 0 || x >= w || y >= h)
      return 0;//zero é sem tile ou vazio
    //retorna a linha e coluna (céluna) do mapa
    return map[y][x];
  }
};

Dai por exemplo, se quiser verificar se o player colidiu com um objeto sólido faça algo assim:

if (tilemap.getTileAt(rectPlayer.x, rectPlayer.y + rectPlayer.h) == 1 || tilemap.getTileAt(rectPlayer.x + rectPlayer.w, rectPlayer.y + rectPlayer.h) == 1)

  colidiu com tile sólido de valor 1

tilemap é o objeto do tipo TileMap

rectPlayer é o retangulo do corpo do player, x/y posilção x e y no mundo, w/h largura/altura do rect do player

 

Observe que, com essa única função no TileMap, você pode implementar colisão estilo plataforma. Não vou entrar nesses detalhes porque isso envolveria uma explicação bem longa, mas você pode estudar esse código aqui da minha engine:

https://github.com/algunsnerds/chora_engine/blob/master/platform/tilemap.cpp

 

É uma engine bem simples, fiz ela apenas como meio de aprender melhor programação. Essa classe ai que uso, você pode ver a outra no mesmo repo chamada Entity que implementa colisão estilo super mario bros. É bem útil pra estudar.

certamente vou dar uma estudada, muito obrigado por essa explicação

 

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


 float a = 0;
 float b =0;
 float a_old = 0;
 float b_old =0;
(...)
else if(ev.type == ALLEGRO_EVENT_TIMER)
        {

	    a_old = a;
        b_old = b;
(...)
else if(map[i][j] == 2)
                {
                    //al_draw_bitmap(pedra,(j * BlockSize) + a, (i * BlockSize )+ b,0); mover essa linha para baixo
                    if (colisao(px, py, 32, 32, (j* BlockSize) + a, (i*BlockSize+ b), 32, 32) == true)
                    {
                        cima = false;
                        baixo = false;
                        esquerda = false;
                        direita = false;
                        a = a_old;
                        b = b_old;
                    }
                    al_draw_bitmap(pedra,(j * BlockSize) + a, (i * BlockSize )+ b,0);
                }

Veja se assim funciona

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

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...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!