Ir ao conteúdo
  • Cadastre-se

C Maze Escape - Sprite Personagem Allegro


erique

Posts recomendados

@Benjamin Breeg @TYSQUARE89 Continuando à saga maze escape.

 

Estou tentando fazer um sprite pro personagem, para ele andar no mapa.

 

Mas estou com dúvida agora para tirar suas dimensões, eu estava tentando seguir esse vídeo

 

Mas no meu caso deve ser um pouco diferente, como tirar essas medidas.

 

O personagem está na pasta _img

 

Obs: Código agora está bem estruturado.

Maze Escape - Projeto.zip

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

As medidas variam de jogo para jogo, geralmente os jogos de 2d usam de 32x32, 64x64, 128x64. Isso já é visado antes de criar os gráficos, pois a pessoa tem uma ideia do tamanho dos items, tiles, objetos, etc.

Na montagem de um sprite, onde temos uma sequência de movimentos, é necessário que cada frame respeite o tamanho do personagem individual, não ultrapassando os limites da imagem.

Para tirar as medidas no momento do desenho use um Grid, no gimp você pode configurar em Imagem -> Configurar Grid

Assim você tem uma ideia de onde desenhar.

 

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

Sim por padrão o tamanho é uma potencia de 2 mas não saberia te dizer porque os computadores trabalham dessa forma. Ex.

 

2 elevado a quinta = 32

2 elevado a sexta = 64

2 elevado a setima = 128

 

e por ai vai...

 

Atualmente as API graficas estão mais relaxadas quanto a esse padrão, porém você sabendo o tamanho certo de cada sprite facilita muito, o ideal é pegar as folhas de sprites com imagens 32x32, 64x64 etc etc. Essa do Mario teria que trabalhar ela pra ficar certinha e ai pegar as medias como o cara fez no vídeo.

 

Tente isso.

 

#include <allegro.h>

#define baixo 0
#define esquerda 32
#define direita 64
#define cima 96

int x = 0;
int y = 400;
int spriteX = 32;
int spriteY = baixo;

int main()
{
    allegro_init();
    install_keyboard();
    set_color_depth(32);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);

    BITMAP* buffer = create_bitmap(800, 600);
    BITMAP* heroi = load_bitmap("heroi.bmp", NULL);

    while(!key[KEY_ESC])
    {
        if (key[KEY_RIGHT]){
            spriteY = direita;
            x += 5;
        }
        else if (key[KEY_LEFT]){
            spriteY = esquerda;
            x -= 5;
        }

        else if (key[KEY_UP]){
            spriteY = cima;
            y -= 5;
        }

        else if (key[KEY_DOWN]){
            spriteY = baixo;
            y += 5;
        }

        if (!key[KEY_RIGHT] && !key[KEY_LEFT] && !key[KEY_UP] && !key[KEY_DOWN]){
            spriteX = 32;
        } else {
            spriteX += 32;
        }

        if (spriteX > 64){ // limite do sprite
            spriteX = 0;
        }

        masked_blit(heroi, buffer, spriteX, spriteY, x, y, 32, 32);
        draw_sprite(screen, buffer, 0, 0);
        rest(80);

        clear(buffer);
    }
    destroy_bitmap(buffer);
    destroy_bitmap(heroi);
    return 0;
}
END_OF_MAIN()

Folha de Sprite.

heroi.zip

 

Seguindo o exemplo do Mario que ele fez, editei um bitmap com as mesmas características ou quase...

 

A imagem tem 593x314, se os sprites estiverem distribuídos corretamente é so fazer uma continha basica:

 

São 6 sprites na horizontal  portanto 593 / 6 que eu arredondei para 100 ja que tem uma sobra ali e 2 sprites na vertical portando 314 / 2 = 157. Então cada sprite na folha ficou tem 100x157

 

Agora fica fácil colocar os dados ali no programa, usei o exemplo dele sem a parte do cenário, também coloquei alguns comentários.

 

#include <allegro.h>

void control();

// x e y é onde o frame esta localizado no buffer (posicao da imagem na tela)
// wx e wy são as coordenadas do canto superior esquerdo do sprite
// w e h é a largura e altura de cada frame

// 0 é o canto superior esquerdo da fileira de sprites de cima
// 157 é o canto superior esquerdo da fileira de sprites de baixo
// wx faz a animacao do mario andar pra direita
// wy faz a animacao do mario andar pra esquerda
struct obj {int x, y, wx, wy, w, h;};
struct obj p {300, 370, 0, 157, 100, 157};

int nTile = 0, dir = 0, i;

int main()
{
    allegro_init();
    install_keyboard();
    set_color_depth(32);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);

    BITMAP* buffer = create_bitmap(800, 600);
    BITMAP* mario = load_bitmap("mario.bmp", NULL);

    while(!key[KEY_ESC])
    {
        control();

        masked_blit(mario, buffer, p.wx + nTile*100, p.wy - dir*157, p.x, p.y, p.w,p.h);
        draw_sprite(screen, buffer, 0, 0);
        rest(80);

        clear(buffer);
    }
    destroy_bitmap(buffer);
    destroy_bitmap(mario);
    return 0;
}
END_OF_MAIN()

void control()
{
    if (key[KEY_LEFT]) {
        p.x -= 20;
        dir = 0;
        nTile--;
    } else if (key[KEY_RIGHT]) {
        p.x += 20;
        dir = 1;
        nTile++;
    } else {
        nTile = 5;
    }

    if (nTile < 0) { // sprite 0,1,2... e repete o ciclo
        nTile = 2;
    }

    if (nTile > 2 && nTile != 5) { //seleciona sprite n 5 quando personagem esta parado
        nTile = 0;
    }

}

 

Folha de sprite:

mario.zip

 

 

 

 

 

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

Perfeito, esse primeiro personagem gostei dele, acho que vou tentr usar ele por hora.

 

Consegui implementar no código atual, porém agora precisa-se ajustar a colisão dele novamente, já que o personagem é 32 por 32 pixels.

 

Não me incomodo com o tamanho do personagem atual, achei que até da uma impressão de 3D falsa, já que a cabeça dele fica no muro.

 

Eu estava tentando mexer na colisão dele, mas não deu muito certo

 

        if (key[KEY_RIGHT]){
            spriteY = direita;
            if(mapa[x][y+1*BLOCO] != M){
            x += 5;
            //heroi.y++;
            }
        }
        else if (key[KEY_LEFT]){
            spriteY = esquerda;
            if(mapa[x][y-1*BLOCO] != M){
            x -= 5;
            //heroi.y--;
            }
        }

        else if (key[KEY_UP]){
            spriteY = cima;
            if(mapa[x-1*BLOCO][y] !=0 ){
            y -= 5;
            //heroi.x--;
            }
        }

        else if (key[KEY_DOWN]){
            spriteY = baixo;
            if(mapa[x+1*BLOCO][y] !=0 ){
            y += 5;
            //heroi.x++;
            }
        }

        if (!key[KEY_RIGHT] && !key[KEY_LEFT] && !key[KEY_UP] && !key[KEY_DOWN]){
            spriteX = 32;
        } else {
            spriteX += 32;
        }

        if (spriteX > 64){ // limite do sprite
            spriteX = 0;
        }

        int i;
        int j;
        for( i=0; i<LINHAS; i++){
            for(j=0; j<COLUNAS; j++)
            {
                if(mapa[i][j]==M)
                {
                    blit(muro,buffer,0,0,j*BLOCO,i*BLOCO,BLOCO,BLOCO);
                }
                if(mapa[i][j]==T)
                {
                    blit(trilha,buffer,0,0,j*BLOCO,i*BLOCO,BLOCO,BLOCO);
                }
                if(mapa[i][j]==I)
                {
                    blit(item,buffer,0,0,j*BLOCO,i*BLOCO,BLOCO,BLOCO);
                }
                if(mapa[i][j]==S)
                {
                    //blit(trilha,buffer,0,0,j*BLOCO,i*BLOCO,BLOCO,BLOCO);
                    blit(saida,buffer,0,0,j*BLOCO,i*BLOCO,BLOCO,BLOCO);
                }
                if(mapa[i][j]==F)
                {
                    blit(fundo_g,buffer,0,0,j*BLOCO,i*BLOCO,BLOCO,BLOCO);
                }
                masked_blit(heroi2, buffer, spriteX, spriteY, x, y, 32, 32);
            }

Poderia dar um help nisso?

 

The Maze Escape.zip

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

Então o problema é que para esse tipo de colisão  precisa que o sprites sejam da mesma dimensão, para não ter que usar sprites pequenos pra fazer labirintos grandes a solução seria usar a camera, um recurso que você pode rolar a tela e assim poder usar mapas realmente grandes.

 

Esse fim de semana eu vou ter um tempo de mexer ai tento implementar a camera para ver como fica, uma solução é tentar achar folhas de sprites com sprites 20x20.

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

@Benjamin Breeg

8 horas atrás, Benjamin Breeg disse:

Então o problema é que para esse tipo de colisão  precisa que o sprites sejam da mesma dimensão, para não ter que usar sprites pequenos pra fazer labirintos grandes a solução seria usar a camera, um recurso que você pode rolar a tela e assim poder usar mapas realmente grandes.

 

Esse fim de semana eu vou ter um tempo de mexer ai tento implementar a camera para ver como fica, uma solução é tentar achar folhas de sprites com sprites 20x20.

 

Encontrei somente alguns já nessas dimensões, vou pesquisar mais um pouco pra ver se acho mais.

 

Já eu posto se achei algo a mais, para começar a trabalhar ainda hoje nisso.

 

anime.zip

Link para o comentário
Compartilhar em outros sites

Realmente não encontrei um já pronto, com as dimensões que seja diferente do que já postei.

 

Vou utilizar essa personagem então, bom que todos dessa pasta anime, usam as mesmas dimensões, então se precisar trocar de personagem não vai ser necessário ficar reajustando o código.

 

heroi.png

 

Eu estava tentando mudar para a proporção dessa imagem, mas não deu muito certo tmb.

#define baixo 0
#define esquerda 20
#define direita 40
#define cima 60

int x = 25;
int y = 85;
int spriteX = 20;
int spriteY = baixo;

Agora deve mudar algo, nessa lógica, visto que não temos um sprite longo, com várias animações, somente 2 em cada movimento, para simular o "andar" do personagem.

 

Vou ir testando aqui, mas se já puder ajudar nesse quesito.

 

@TYSQUARE89 @Benjamin Breeg

The Maze Escape.zip

Link para o comentário
Compartilhar em outros sites

Essas definições nao tem relação com a colisão, elas são responsáveis pelas coordenadas para definir a orientação do boneco dentro da folha de sprites, se você reparar nessa folha de sprites pode ver que numa faixa o boneco esta olhando para frente (baixo), esquerda, direita e de costas (cima) portanto quando você aperta seta pra baixo (boneco de frente) ele vai para a coordenada 0 do canto superior esquerdo da folha que corresponde a animação do boneco andando pra baixo, se selecionar seta para cima ele vai para a coordenada 96 que corresponde a animação do boneco andando pra cima e por ai vai.

 

Se você mudar a folha vai ter que mudar os valores, o ideal é pegar folhas que dividindo a largura pela quantidade de sprites na horizontal e a altura pela quantidade de sprites na vertical de valores iguais, isso facilita muito na hora de trabalhar com sprites animados.

 

Ex. 288 / 3 e 384 / 4 = sprites de 96x96.

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

Sim e também é interessante frisar que a disposição dos sprites na folha segue o mesmo sentido.

 

BAIXO

ESQUERDA

DIREITA

CIMA

 

na sequencia pelas colunas.

 

Eu estou vendo uma forma melhor de fazer isso, algo que seja mais eficiente e não muito confuso, na pratica tem muitas formas de fazer.

 

Link para o comentário
Compartilhar em outros sites

Então seguindo essa lógica ficaria algo assim para começar.

 

#define baixo 0
#define esquerda 40
#define direita 80
#define cima 120


int spriteX = baixo;
int spriteY = 20;

 

?

adicionado 0 minutos depois

Contando de 40 em 40, já que tem apenas 2 animações para cada movimento

adicionado 0 minutos depois

é cada animação é de 20x20

Link para o comentário
Compartilhar em outros sites

Na verdade você so define a posicao do canto superior esquerdo.

 

se são por ex.. 2 sprites na horizontal e 4 na vertical

 

#define baixo 0
#define esquerda 20
#define direita 40
#define cima 60

 

Esse espaço da animação você define na própria função masked_blit como no exemplo do mario multiplicando x pela largura e y pela altura a cada iteração do loop ou na função de controle como no exemplo daquele personagem de rpg

 

if (!key[KEY_RIGHT] && !key[KEY_LEFT] && !key[KEY_UP] && !key[KEY_DOWN]){
            spriteX = 20;
        } else {
            spriteX += 20;
        }

        if (spriteX > 40){ // limite do sprite
            spriteX = 0;
        }

heroi_varios.zip

 

Eu lembrei que tinha as animações desse personagem naquele jogo da princesa, veja se você consegue fazer uma folha com aquela mesma disposição, preciso aprender como aprender os sprites separados porque não é obrigatório estar na folha.

 

 

 

Link para o comentário
Compartilhar em outros sites

Fiz as alterações.

 

PAyQasTUTUahKv9Kx3OEhA.png

 

#define baixo 0
#define esquerda 20
#define direita 40
#define cima 60

int x = 25;
int y = 85;
int spriteX = 20;
int spriteY = baixo;

 

É no game está assim.

 

        if (key[KEY_RIGHT]){
            spriteY = baixo;
            spriteX += 20;
            if(mapa[x][y+1] != M){
            x += 1;
            //heroi.y++;
            }
        }
        else if (key[KEY_LEFT]){
            spriteY = baixo;
            spriteX += 20;
            if(mapa[x][y-1] != M){
            x -= 1;
            //heroi.y--;
            }
        }

        else if (key[KEY_UP]){
            spriteY = baixo;
            if(mapa[x-1][y] !=0 ){
            y -= 1;
            //heroi.x--;
            }
        }

        else if (key[KEY_DOWN]){
            spriteY = baixo;
            if(mapa[x+1][y] !=0 ){
            y += 1;
            //heroi.x++;
            }
        }

        if (!key[KEY_RIGHT] && !key[KEY_LEFT] && !key[KEY_UP] && !key[KEY_DOWN]){
            spriteX = 20;
        } else {
            spriteX += 20;
        }

        if (spriteX > 40){ // limite do sprite
            spriteX = 0;
        }

e o blit do sprite

 

masked_blit(heroi2, buffer, spriteX, spriteY, x, y, 20, 20);

 

adicionado 0 minutos depois

Imagino que o próximo passo agora são as regras nos if, para a colisão, já que parece que a animação está funcionando.

adicionado 22 minutos depois

Primeiras 2 posições do sprite, referente para cima

 

x = 0

y = 20

 

&

x = 20

y = 20

 

Segunda posição, referente ao sprite pra direita

 

x = 40

y = 20

&

x = 60

y = 20

 

Terceira posição, referente ao sprite pra baixo

 

x = 80

y = 20

&

x = 100

y = 20

 

Quarta posição, referente ao sprite de LEFT, esquerda

x = 120

y = 20

&

x = 140

y = 20

adicionado 23 minutos depois

Sabendo disso.

 

#define baixo 80
#define esquerda 120
#define direita 40
#define cima 0

 

Não ficaria assim?

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

Você só muda o offset Y da imagem, quando for usar outra linha de sprites, como se você estivesse colocando:

cima           Y = 0

baixo          Y = 20

esquerda   Y = 40

direita         Y = 60

 

No caso dessa ultima imagem de sprite, não precisa tirar do 0, segue as coordenadas:

 

image.png.85c8a5bf68479abde7b67141ed58fafa.png

sendo (x,y)

Link para o comentário
Compartilhar em outros sites

Consegui algo aqui.

 

O personagem ta se movimentando, com os sprites corretos, mas nem todos.

 

Aparentemente, ele ta andando só com o 1 sprite de cada lado. provavelmente por causa disso.

        if (key[KEY_UP]){
            spriteX = cima;
            if(mapa[x-1][y] != M ){
            y -= 1;
            //heroi.x--;
            }
        }

        else if (key[KEY_LEFT]){
            spriteX = esquerda;
            if(mapa[x][y-1] != M){
            x -= 1;
            //heroi.y--;
            }
        }

        else if (key[KEY_DOWN]){
            spriteX = baixo;
            if(mapa[x+1][y] != M ){
            y += 1;
            //heroi.x++;
            }
        }

        else if (key[KEY_RIGHT]){
            spriteX = direita;
            if(mapa[x][y+1] != M){
            x += 1;
            //heroi.y++;
            }
        }

        if (!key[KEY_RIGHT] && !key[KEY_LEFT] && !key[KEY_UP] && !key[KEY_DOWN]){
            spriteX = 20;
        } else {
            spriteX += 20;
        }

        if (spriteX > 160){ // limite do sprite
            spriteX = 0;
        }

Mudei também o limite do sprite, porque já que é coordenada X do sprite, o limite da imagem é 160, me corrijam se eu estiver errado

The Maze Escape.zip

Link para o comentário
Compartilhar em outros sites

@erique Perceba que cada direção possui 2 frames, então agora você precisa de uma "flag" ou usando o ternário ? para indicar qual dos 2 está sendo usado, para poder dar o efeito certo, exemplo:

#define W 10 // tamanho de cada frame

        else if (key[KEY_RIGHT]){
			//será escolhido um frame da direita que ainda nao foi
			//usado, começando em define->direita
			spriteX = (spriteX != direita ? direita : (direita+W));

            if(mapa[x][y+1] != M){
            x += 1;
            //heroi.y++;
            }
        }

 

adicionado 3 minutos depois

@erique P.S: eu  acho coloquei errado na imagem acima, pois cada direção é somada pela quantidade de frame, mas se o frame é de 20x20, a imagem está correta.

Link para o comentário
Compartilhar em outros sites

@TYSQUARE89 Parece um pouco mais fluido, mas talvez eu não consiga visualizar com perfeição ainda, devido a colisão não estar muito bem ajustada ainda.

 

        if (key[KEY_UP]){
                spriteX = (spriteX != cima ? cima : (cima+W));
            //spriteX = cima;
            if(mapa[x-1][y] != M ){
            y -= 1;
            //heroi.x--;
            }
        }

        else if (key[KEY_LEFT]){
                spriteX = (spriteX != esquerda ? esquerda : (esquerda+W));
            //spriteX = esquerda;
            if(mapa[x][y-1] != M){
            x -= 1;
            //heroi.y--;
            }
        }

        else if (key[KEY_DOWN]){
            spriteX = (spriteX != baixo ? baixo : (baixo+W));
            //spriteX = baixo;
            if(mapa[x+1][y] != M ){
            y += 1;
            //heroi.x++;
            }
        }

        else if (key[KEY_RIGHT]){
			//sera escolhido um frame da direita que ainda nao foi
			//usado, comecado pelo definido em define->direita
			spriteX = (spriteX != direita ? direita : (direita+W));

            if(mapa[x][y+1] != M){
            x += 1;
            //heroi.y++;
            }
        }

 

Link para o comentário
Compartilhar em outros sites

@erique Entendi a lógica, caso o local for diferente desse tile M, é possível mover. Vou testar o código aqui, se puder passar os arquivos agradeço.

P.S: eu criei uma pasta no Google Drive, lá da para alterar e compartilhar mais rápido entre nós três, se puderem passar um gmail.

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

@erique eu fiz algumas modificações no sistema de colisão e movimento, tem três observações:

 

1) O jogador só pode movimentar de tile em tile(20 px), sendo que para mover menos do que isso, é necessário que seja feito a contagem do movimento, e quando o usuário for mover para outro tile é feito o teste de colisão.

Isso resolve o problema do player se 'perder'  no mapa e passar nos tiles. 

 

2) Adicionei algumas variáveis, MAPX e MAPY, elas identificam o próximo tile na matriz do mapa, e mantem a lógica de movimento de acordo com a colisão.

 

3) Agora os frames estão trocando corretamente.

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

8 horas atrás, TYSQUARE89 disse:

@erique eu fiz algumas modificações no sistema de colisão e movimento, tem três observações:

 

1) O jogador só pode movimentar de tile em tile(20 px), sendo que para mover menos do que isso, é necessário que seja feito a contagem do movimento, e quando o usuário for mover para outro tile é feito o teste de colisão.

Isso resolve o problema do player se 'perder'  no mapa e passar nos tiles. 

 

2) Adicionei algumas variáveis, MAPX e MAPY, elas identificam o próximo tile na matriz do mapa, e mantem a lógica de movimento de acordo com a colisão.

 

3) Agora os frames estão trocando corretamente.

 

Agora sim, está perfeito.

 

Só notei que nas primeiras compilações que fiz, quando fechava o programa, o mesmo continuava com o bug de não fechar totalmente, fica meio aberto em segundo plano, no gerenciador de tarefas do windows, da para ver

 

A6XGqax5Tm_Q5vCzXqVhrQ.png

 

Eu recompilei para garantir, nas últimas vezes que testei não ocorreu mais, dei uma revisada também para ver se tinha removido algo, tirando o que estava comentado, não vi diferença, espero que não ocorra mais.

 

Também adicionei a colisão com o item para ele somar nos pontos, timer e desaparecer.

 

Ficou show de bola, obrigado pelo help. @TYSQUARE89 @Benjamin Breeg

 

Vou vendo agora o que precisa ser melhorado, e adicionado, e a medida que for tendo as dúvidas crio outro tópico. :thumbsup:

 

Segue o código para conhecido :)

 

The Maze Escape.zip

  • Curtir 2
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!