Um momento
Aula 11
Cursos / SDL - Desenvolvimento de Jogos - libsdl SDL2
Como Carregar Imagens de PNG JPG TIF para Jogo no SDL2 com o SDL Image

Nesta aula aprendemos a carregar imagens de formato que não é BMP, como o JPG, PNG e TIF. Como desafio, temos que mostrar uma imagem de um troféu após o jogador pisar no azulejo de saída do labirinto.

Primeiro instale a biblioteca SDL_image. No caso do Ubuntu, o seguinte comando pode ser usado:

sudo apt install libsdl2-image-dev

Use o seguinte include quando tiver que usar as funções da biblioteca:

#include <SDL2/SDL_image.h>

O seguinte argumento deve ser adicionado ao comando do compilador:

-lSDL2_image

Primeiro de tudo, acione a biblioteca na função de iniciar o jogo com a função IMG_Init. Para mais informações, veja a documentação.

Também deve-se fechar a biblioteca na função de desligar o jogo: use IMG_Quit.

Para carregar uma imagem, use IMG_Load. O argumento é o caminho do arquivo. O valor de retorno é um ponteiro para uma superfície: SDL_Surface*. Não se esqueça de liberar a memória com o SDL_FreeSurface toda vez que alocar memória para uma nova superfície.

Summary

Aula de Sdeli2: Implementando o Game Over

Introdução

Na aula de hoje, aprendemos a implementar a funcionalidade de game over em um jogo utilizando a biblioteca Sdeli2. Vamos mostrar uma imagem de um troféu quando o jogo terminar.

Estrutura do Jogo

O jogo termina quando o jogador alcança a saída do labirinto. A saída é identificada por um retângulo vermelho. A posição do jogador será comparada com a posição da saída, e ao se encontrarem, o jogo será encerrado.

Implementação do Game Over

  • Criação de uma variável booleana acabou que indica se o jogo terminou.
  • Inicialmente, acabou é definida como false.
  • No loop do jogo, após processar a entrada do jogador, verificamos se acabou ainda é false. Se a posição do jogador coincidir com a da saída, acabou se torna true.

Função para Verificar Game Over

A função jogo_deve_acabar() retorna true se a posição do jogador for igual à posição da saída:

bool jogo::deve_acabar() {
    return (posicao_jogador.x == posicao_saida.x && posicao_jogador.y == posicao_saida.y);
}

Prevenção de Movimento Após Game Over

Quando o jogo acaba, não deve processar mais a entrada do jogador.

if (!acabou) {
    processar_entrada_do_jogador();
}

Exibindo a Imagem de Vitória

Adicionamos a exibição de uma imagem de troféu centralizada na tela ao final do jogo.

Carregando a Imagem

Usaremos a biblioteca SDL_image para carregar imagens em formato PNG. Para instalar essa biblioteca no Ubuntu, utilize:

sudo apt install libsdl2-image-dev

Código para Carregar e Mostrar a Imagem

superficie_imagem_final = IMG_Load("trofeu.png");
if (!superficie_imagem_final) {
    SDL_Log("Erro ao carregar imagem: %s", IMG_GetError());
}

Centralizando a Imagem

Para centralizar a imagem, calculamos a posição com base na largura e altura da janela e da imagem:

destino_imagem_final.x = (window_width - superficie_imagem_final->w) / 2;
destino_imagem_final.y = (window_height - superficie_imagem_final->h) / 2;

Testando o Jogo

Após as implementações, ao alcançar a saída, a imagem do troféu aparecerá no centro da tela, indicando o final do jogo. A tela não permitirá mais movimentação após o término.

Conclusão

Estamos finalizando a aula de hoje. Agradecemos a todos que assistiram. Por favor, deixem seu like e se inscrevam no canal para receber notificações de futuras aulas.

Até a próxima!

Video Transcript

Olá pessoal, estamos de volta com mais uma aula de Sdeli2. Vamos continuar, vamos aprender como fazer o game over e mostrar uma imagem de um formato PMG no final do jogo. Então o que vai ser esse game over? O jogo acabou. Bem, o jogo acaba quando a gente com a outra saída. O jogo é tudo laberinto, né? Então eu vou andar até o final, que nesse caso aqui é o retangulo quadradinho com a cor meio que vermelha. Quando eu entro, quando eu dar o passo e entrar na saída, eu quero terminar o jogo. O jogo acabou. E quando isso acontecer, você não pode mais movimentar. E uma imagem de um troféu deve aparecer no centro da tela. Então vamos lidar com a determinação de que o jogo acabou ou não. Então o jogo acaba quando a posição do jogador bate com a posição da saída do laberinto. Lembre-se de que se você for no jogo .h, um dos atributos de um objeto de jogo é a posição saída. Então temos a posição saída. Também temos a posição do jogador. Podemos comparar esse x e y desses dois e se bater, significa que o jogo acabou. Agora para indicar que o jogo acabou ou não, eu vou criar uma variável. Então deixa eu adicionar aqui. Vou criar um bool. Acabou. E no jogo, vou fazer cpp. Quando você iniciar no constructor, o jogo ainda não acabou. Então vou falar acabou igual a false. Agora quando você estiver lá no rodar e no game loop, depois de processar a entrada do jogador, nós vamos checar se o jogo ainda não acabou e se o jogo deve acabar, nós mudamos a cabo para true. Então se não acabou ainda e vamos dizer que o jogo deve acabar. Vou criar essa função de a real. Eu disse o que é. Acabou. Então basicamente é o seguinte, se o jogo acabou false, o jogo ainda não acabou. A gente vai checar se o jogo deve acabar. Se o jogo já estiver acabado, acabou vai ser true, esse aqui vai ser false, então esse f vai ser pular. Só vai pintar na tela. Agora o jogo deve acabar. Deve eu criar essa função. Essa função retorna bull se o jogo deve acabar. Isto é, se a posição do jogador for a mesma posição da saída do labirinto. Vou no jogo .h, deixo eu definir aqui como um membro público, uma função pública, retorna um bull, o jogo deve acabar sem nenhum argumento. Vamos definir essa função no arquivo jogo.cpp. Pode ser que eu coloquei um lugar aqui, deixa eu criar em baixo. Então vamos lá bull, espaço de jogo, dois pontos, dois pontos, o jogo deve acabar. Abre parênteses sem nenhum parâmetro. Abre chaves. Então o jogo deve acabar se a posição do jogador x foi igual à posição da saída x e a posição do jogador y foi igual à posição da saída y. Obviamente nós estamos usando um mapa de azulejo, então nós esperamos que a baixa da gente checa o x da posição do ponto acima à esquerda do retangulo, nesse caso quadrado. Não é movimento livre de mapa livre. Então o jogo deve acabar se a posição do jogador x foi igual a dois sinais de igual a dois para comparar, posição saída x e, né, 100%, posição do jogador ponto y igual ao igual, posição saída y ponto y. Eu posso retornar sem ter que fazer. Se essa posição do jogador x foi igual à posição saída x e a posição do jogador y foi igual à posição saída x, nesse caso vai ser true, então o jogo deve acabar. Se alguma dessas condições falhar vai tornar fós, então o jogo não deve acabar ainda. Vamos voltar aqui no processo de entrada do jogador. Agora eu queria fazer o seguinte, queremos prevenir o jogador de se mover depois que o jogo acabou. Então para isso a gente não vai mais processar entrada do jogador se o jogo acabou. Vamos ver aqui no quit. Se for quit para sair do jogo, isso a gente pode fazer ainda, a gente só não quer processar entrada do jogador. Então eu vou falar se o jogo ainda não acabou eu posso processar entrada do jogador. Então f, exclamação acabou, processar entrada do jogador. Enquanto o jogo não acabou eu vou de processar. Vamos ver se não tem nenhum problema. Vou compilar e rodar o jogo. Vou começar a andar. A gente poderia até prevenir processar enquanto essa mensagem de objetivo aparecesse, mas não acesse isso para você fazer. Então quando eu bater na saída, se notes que eu não consigo mais sair, eu estou tentando apertar na seta para a esquerda, mas ele não movimenta mais. Então o jogo acabou. Então aquela flag, aquela flag acabou, se torna o true e a processar entrada do jogador não é mais chamado. Agora bem, agora a gente pode mostrar uma imagem. A gente sabe que quando o jogo acaba a gente deve mostrar a imagem. Então aqui no blade surface, na sação de blade surface, depois colocar depois de tudo. Você faz o mapa, o etângulo, quando estiver pintando, pintando, pintando, pintando, eu quero mostrar aqui fora do if, porque não é parte do mostrar mensagem de objetivo. Eu vou dar o blade surface da imagem de vitória. Superfície, eu vou criar essa variável já. Superfície da imagem, sei lá, final, vamos dizer final, vitória. Eu quero toda imagem, não. Não quero parte da imagem. E vou colar na window surface, pintar na window surface e o endereço de destino da imagem final que eu vou criar já. Mas isso não quer que apareça sempre, né? Se eu colocar essa maneira aqui, sempre vai aparecer no meio do jogo. Então a gente só vai dar esse blade surface, mostrar a imagem final se o jogo acabou. Então, se acabou, você vai dar o blade surface e mostrar essa imagem final. Agora vamos criar essas variáveis. Depois da imagem inicial, vou criar aqui. Então a gente vai ter que criar superfície da imagem final e destino da imagem final. Opa, final de final. Bem, destino da imagem final é simples. Fazer um sdare rack como tipo igual, abre as chaves, ponto e vírgula. Ao destino eu quero que apareça no centro. Então seria aquela mesma estratégia. Pega a largura da janela, window if, subtrai a largura da superfície, nesse caso superfície da imagem final que a gente vai criar já, já. E pega isso tudo, coloca parentes ao redor, dividir por dois. Agora, por y, a mesma coisa. Abre parentes, window height, que é a altura da janela, menos a superfície. Opa, eu esqueci de dizer superfície da imagem final traço maior que w, que é a largura da superfície da imagem. Então no caso da y que seria superfície da imagem final, traço maior que h, que vai te dar a altura. Então pega tudo isso, dividir por dois, poder centralizar. Então não importa o w e o h dessa superfície da imagem final, a gente já sabe que não é usado. Inicialmente na hora de colar. Pronto, agora superfície da imagem final. Essa aqui que eu queria te mostrar como carregar uma imagem que não seja BNP, por exemplo, PNG. Então vou aqui na web, fazer uma busca, por uma imagem de um troféu. O troféu clipart como a palavra chave. Se eu gostei dessa primeira imagem, eu cliquei nela e eu salvei essa imagem. Bem, a imagem é bem grande. Deixa eu mostrar aqui. Então troféu, PNG 1.2 megabytes. Então vou abrir o GIMP e vou arrastar pro GIMP. Opa, tem que criar, fechar. Vou fechar tudo, descartar, agora fazer de novo, arrasto lá. A imagem é bem grande, vou clicar a imagem e redimensionar. A gente sabe que a altura da minha janela de jogo é 480, vou botar a metade de 240. Então nesse caso seria 182 por 240. Então tá bom essa dimensão, esse tamanho da imagem. Então vou clicar arquivo, eu posso salvar ou poder exportar, salvar a imagem. Ah, não dá pra salvar o que é o formato do GIMP, então tem que clicar exportar. Vou clicar sobre escrever troféu, PNG, que ele vai exportar e subscrever. Pronto. Então eu redimensionei a imagem, acho que esse tamanho tá bom pro jogo, vai cabê, vai cabê lá na tela do jogo. Então com isso agora a gente vai partir pra carregar a imagem no formato PNG, nesse caso. PNG. Então a gente vai usar a seguinte, a biblioteca vai ser SDL image. Tá bom? Ah, então deixa eu ver aqui. No meu caso, pra poder instalar isso, SDL image 2.0, eu posso, eu tô usando o bonto, então deixa eu ver o bonto aqui, qual é o nome do pacote. Eu acho que o nome vai ser Lebe, SDL 2, traço, IMG, traço deve, alguma coisa assim. Lebe, SDL 2, IMG. Deixa eu ver. Eu acho que vai ser isso. Não achou. Ah, SDL 2. Ah, IMG. Oh, achei aqui. Não é IMG, image, image, ok. Lebe, SDL 2, traço, image, traço deve, ok. Então deixa eu ver no terminal aqui. Tudo, apeter, install. Lebe, SDL 2, traço, image, traço deve. Ah, vamos lá checar o, o SCR, eh? Barra include LS, barra o SCR, barra include, barra, SDL 2. Vou dar o grab, pipe grab, image, tá aqui o arquivo.h. Ah, então, instalei, né? Biblioteca. Deixa eu já modificar o linker, se lembra que tem um linker. Ah, vai aparecer depois, eu depois te mostro, então vamos lá. Ah, estou aqui na documentação no navegador, do SDL, image, você pode clicar aqui no documentation. Lebe, SDL, port org, barra projects, barra, SDL, underscore, image. Ah, aqui tem get insta, ele mostra como instalar e tal e tal, mas o que importa é que vai ter aquele menu lance de init, se lembra que a gente fez, ah, iniciar. A gente fez o init do SDL, init do 3F, também vai ter o init do SDL, image. Então vamos ver como é que faz aqui, clicking, ah, init. Então ele mostra aqui como é que você faz o init, no documentação, tá? Ah, similar, né? Img, underscore, init, aí você tem que passar flags nesse caso, ah, que tipo de formato você gostaria de poder carregar. Nesse caso, tem essas flags aqui, img init, opg, img init, png, img init, tif. Então no caso, o poder é só usar img, underscore, init, underscore, png. Mas para te mostrar como é que também cai a gljpg, você faz o seguinte, você faz um pipe, né? Img init, png. O que é que está acontecendo aqui? Fazendo o war, operação de lógica, né? De bit, né? Lembra, 0 e 1, quando você tem, por exemplo, 0, 1, or, 0, 0, 0. Quando você vai a sua operação, isso vai dar o quê? Vem, você começa aí, vamos ver. O 0 e 1, né? O primeiro, o carácter aqui, o 0 e 1. Ou é 0 ou 1, nesse caso na operação de bit, vai ser 1, tá? Ou no segundo, 1 ou 1 ou 0, vai ser 1. E no 0, 0 é 0. 0, 0 é 0, né? Porque o or, a operação or é o seguinte, quando você tem 0 e 1 é 1. Quando tem 1 e 0 é 1. Quando tem 0 e 0 é 0. Quando você tem 1 e 1 é 1, tá? Tá bom? Tá bom. Se você soubesse essas coisas, acumendo você a estudar o sistema binário e operações lógicas, tá? Nesse caso, or. Então, se você faz o or, bitwise, aí esse cara vai retornar eles aqui. Retorna uma bitmask com todas loaders iniciadas, ok, inundado. Então, para ele comparar se carregou certo ou não, ele faz o and bitwise, que é o... E compara com as flags, ok? Então, vamos lá, pegar essas coisas, colocar dentro de uma flags. Flag é... Então, você vai unir com flags. Vamos chamar a int. Sei lá, vou usar o mesmo nome que eles usaram, inether. Então, para poder fazer o negócio, é o seguinte, você pega o inether, faz o and bitwise com flags. E se for diferente, vai ter eu. O que é que é isso, né? Vamos supor que o flag seja esse 1, 0, 0. Tá? Se eu pegar esse inether e fazer o and com flags, eu espero que seja a mesma coisa, se dessa é. O que é que é o and, né? Explicado, hein, você não sabe? And, vai ser assim. 0 e 0, 0. 0 e 1 é 0. 1 e 0 é 0. E só é 1 se cobrou os dois 1. Tá? Então, meio que o oposto do war, né? O war só é 0 se dois for os zeros. E o and só é 1 se os dois for um. Tá bom, então, nesse caso, você faria, por exemplo, se fosse 1, 1, 0, 0. Se você pegar 1, 1, 0, 0 e dar o and com flags. Se fosse o mesmo, né? Daria no que? Então, vai 1 e 1 é 1, 1 e 1 é 1, 0 e 0 é 0, 0 e 0 é 0. Então, darei no mesmo. Então, 1, 1, 0, 0 é igual a 1, 0, 0. Se for igual, não teve erro. Se não for igual, aí deu um erro, né? Isso que acontece aqui. Se você dá esse and e não for igual as flags que você determinou originalmente, então, teve erro. Ah, então, vamos lá, vamos fazer aquele meio lance. Sdl log, não deu certo carregar o sdli image. Por cento s, naquilo você vai ver img get error, sabe? Que é a função que é torna o mensagem de error do sdli image. Eu vou dar o exit 5, sei lá. Qualquer número aí de parentes 0. Operações lógicas, sabe? Esse or, assim, é diferente do duplo, certo? Se quer, é bit por bit. Tá? Ahm... Pronto, então carregou aqui. Agora não se esqueça de descarregar lá no desligar. Como a gente fez o init quando o jogo acabar, né? O jogo sair, na verdade, o programa sair. Ah, cadê o... No função desligado o jogo. Você vai, antes do tf quit, certo? Antes, o que a gente fez é que no final do iniciar, então vai ter que ser no começo. Aqui na hora de desligar. Img underscore quit. Ah, então você pode ver na documentação a mesma coisa. Calvá, então descarrega, descarrega o sdli image. Agora a gente usou img net para poder usar isso. Você teria que fazer o include do sdli image. Lembra o hardware que a gente pegou aqui? Então você faz pound, include, sdli... Ah, eu posso usar o menor que, maior que. sdli2bar sdliandscoreimage.h Vamos ver como é que eu fiz nos outros. Ah, tinha que ter tf. Certo? Vou botar aqui em cima. Ah, tá está. Ele vai dar para o sdli image. Tá está. Ele vai dar problema de linker. Certo, então... Ah, esqueci de uma coisa. Perfície. Eu não terminei de escrever aquela superfície da imagem. Então vou comentar por enquanto. E na hora de dar o blitz acabou, vou comentar por enquanto. Só para poder rodar e ver se não tem problema. Ah, aqui também no comentar o destino da imagem final. Por enquanto. Agora tá, vamos ver o problema. Referência não definida para img net. E não é a função desligar. Vamos jogar o linker aqui. Vê se não for isso. Arquivo makefile na função g++, no comando g++, traço o e tal e tal. Na hora do traço lsdli2, traço lsdli2andscore.tf, adiciona mais um espaço lsdli2, underscore img. Aí carrega... Sem problemas, né? Traço lsdli2andscore imag. Ok. Agora nos resta... Usar as funções do sdli image. Então já carreguei o sdli image, e coloquei as funções de... Carrega a imagem. Vai ser parecido com sdli loadBMP. Eu tá aqui as funções, loading. 3.2 loading. Automatic loading. Não tem a função específica, e tem a função de loading. Tem a função específica, e tem a função de automaticamente detectar o formato. Então eu posso usar essa. img.sdli2andscore load. Tá? Tá aqui o exemplo que mostra. Então vamos lá. Anjogo.cpp. Superfície da imagem final, igual a img.sdli2andscore load. E o caminho, nesse caso, vai ser trofel.png.vgla. O tipo vai ser sdliandscoresurface. Como a gente usou aqui, a gente já tinha carregado... Já dava o include lá na linha 3. Include-qsdli2-sdliandscoreimage.h. Então pode usar essa função. Se tiver problema, ele retorna no. Então, se não tiver superfície da imagem final, se ponou nesse caso, sdli.log, erro ao carregar a imagem, o cento s, não tinha a mesma coisa que eu fiz, e sabe o que vai ser img.getEr, em vez de sdli.getEr, que tinha a superfície da imagem inicial. Vou dar exit, sei lá. Vamos dar 4 para associar a imagem, sei lá. Mesmo eu. Pronto, não se esqueça de dar o free surface no final, sempre quando você aloca, você tem que alocar sdli, free surface, superfície da imagem final. Vamos lá, fez um erro de compilação, correto. Agora vamos dar o, finalmente, a sdli.dst na imagem final, o bleed surface na linha 263. Vou compilar e rodar o jogo, vou lá mover o meu jogador até a saída. Deixa a mensagem inicial, antes de eu mover, porque eu botei 10 segundos, ainda você pode movimentar, na mesma hora que aparecer a mensagem inicial, se você quiser, se você come exercício, você pode prevenir o jogador de fazer algum entrado, de mover enquanto a mensagem e imagem inicial estiverem na tela. É bem similar à mesma neca de face do acabou. Então, tá aí, quando você move lá, não pode mais sair, aparece troféu no meio da tela, certo? E note que essa imagem é de png, é transparente, então, o fundo do troféu aqui, mescou mesmo com o que tinha por trás, que é o mapa com os altos lejos. Você pode comer exercício, mostrar uma mensagem de vitória e tal. Tá bom, pessoal? Muito obrigado por assistir, quanto com o seu apoio, por favor, deixe seu like, se inscreva no canal, se quiser receber notificações, clique naquele sininho, você sabe, né? Então, por essa é só e até a próxima. Até a próxima.
Nenhum comentário ainda (loading...)
Nenhum comentário ainda (loading...)
Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: