Aula 04
Implementação da Colisão do Jogador com o Muro
Summary
Resumo da Aula de SDL: Colisão do Jogador com o Muro
Introdução
- O objetivo desta aula é implementar a colisão do jogador com muros em um jogo utilizando SDL (Simple DirectMedia Layer).
Estrutura do Jogo
- O jogo utiliza um mapa em forma de matriz bidimensional onde:
- 0 representa o chão (atravessável).
- 1 representa o muro (não atravessável).
Implementação da Colisão
-
Função de Mapeamento:
- Após determinar a próxima posição do jogador, a função
mapearCoordenadaParaID
é usada para obter o ID do azulejo na nova posição. - A lógica de mapeamento envolve dividir as coordenadas x e y pela largura e altura dos azulejos (32 pixels).
- Após determinar a próxima posição do jogador, a função
-
Verificação de Atravessabilidade:
- A função
azulejoForAtravessavel
verifica se o ID do azulejo é zero (chão) e retornatrue
. Para qualquer outro ID (incluindo 1, que é o muro), retornafalse
.
- A função
-
Movimento do Jogador:
- O movimento do jogador (para cima, baixo, esquerda, e direita) é realizado com base na tecla pressionada.
- Antes de atualizar a posição do jogador, o código verifica se a nova posição é atravessável.
- Se for atravessável, a posição do jogador é atualizada.
Refatoração do Código
- Para melhorar a organização, foi criada uma função chamada
processarEntradaDoJogador
. - Variáveis globais para a largura e altura da tela, e o tamanho do azulejo foram definidas para evitar hardcoding.
Enumerações
- Foi introduzido o
enum
para definir o tipo de azulejo de forma mais legível (chão e muro) em vez de usar apenas números.
Conclusão
- Após implementar e testar as colisões, é possível mover o jogador somente sobre os azulejos que são atravessáveis.
- O código foi organizado e refatorado para facilitar futuras implementações.
Mensagem Final
- Incentivo aos alunos a deixar comentários, se inscrever no canal e convidá-los para a próxima aula.
Esse resumo sintetiza os principais pontos da aula sobre a implementação da colisão do jogador com muros em um jogo utilizando a biblioteca SDL.
Video Transcript
E o la pessoal estamos de volta com mais uma aula de Sdl.
Vamos agora aprender como fazer a colisão do jogador com o muro.
Então vamos começar.
Temos aqui o jogo, né?
Então cada azulejo preto é atravessável.
É o chão, nós podemos andar sobre ele.
Agora, o azulejo branco não é atravessável.
O azulejo branco é o muro.
Então nós não podemos pular no muro nesse jogo.
Então ele vai ter que bloquear o jogador, né?
Nós vamos implementar a colisão para poder prevenir o jogador de pular o muro ou atravessar o muro.
Agora a gente pode porque não há colisão.
Mas gostaríamos de prevenir o jogador para somente andar sobre os azulejos pretos.
Então para poder fazer isso, se você lembra, o mapa do jogo é um arquivo de texto.
Então cada azulejo é representado pelo número inteiro.
Zero significa o chão, um significa o muro.
Nós vamos usar esse ID, né?
Esse identificador para poder determinar se a próxima posição do jogador é atravessável ou não.
Vamos criar a função mapear, coordinada para o ID do azulejo.
Isto é, se você tiver dano aqui no mapa e você querer ir para a direita, por exemplo, nesse caso, é um muro.
Então vamos pegar aquela próxima posição.
Vamos mapear essa posição x e y para o ID, né?
Que é aquele próximo azulejo.
Esse ID está dentro daquela array de duas dimensões, que armazena o mapa.
Cada elemento da array tem o ID do azulejo.
Nós vamos mapear a coordenada próxima, coordenada que seria do jogador, se ele atravessasse.
Mapa para o ID.
Vamos verificar se o ID daquele azulejo for atravessável.
Isto é o tipo for chão.
Vamos fazer um enão.
Nós vamos deixar ele passar e o muro não vai poder atravessar.
No final, vamos fazer uma repertorização do código para poder extrair toda aquela lógica da entrada do jogador, das setas.
Para uma função externa para organizar melhor o código.
Então vamos começar aqui.
Eu vou criar uma nova função.
Eu estou no arquivo main.cpp.
Antes da função main, eu vou criar outra função chamada mapA coordenada para ID do azulejo.
Essa função abre parênteses, abre chaves.
Ela vai ter com entrada a próxima posição do jogador.
Eu vou chamar isso, vai ter dentro de um sdli rect, essa estrutura.
Eu vou chamar de posição, essa variável.
E a próxima entrada será a array de duas menções do azulejo.
Lembra?
Azulejo.
Vou chamar de int azulejos.
E tem quantas linhas e quantos colunos?
Linhas será determinada pela altura da tela.
480 dividido por 32 será o quê?
10 vezes 32, 320, 320 mais 160, então 15.
E para elementos colunas, vai ser 640, que é a largura da tela, dividido por 32, que é 20.
Como eu chamo isso agora de azulejo, isso é um detalhe que eu quero falar aqui.
Eu tinha falado azulejo como se fosse tijolos, eu usei o nome tijolos, mas eu quero modificar isso.
Eu não acho que tijolos seja um termo propriado aqui, que eu tinha falado na palavra.
Eu acho que falei errado, né?
Então me desculpe, isso na verdade é azulejos, ou ladrilhos, né?
Então todas as instâncias de tijolos, eu vou substituir com a palavra azulejos.
Azulejos.
Idê do tijolo, idê do azulejo.
Tijolo, codo tijolo será codo azulejo.
E acho que tem também uma variável tamanho do tijolo, a maior do azulejo.
Tá bom?
Deixa eu só adicionar também a saída dessa função.
A saída mapear coordenada para idê do azulejo irá retornar o idê do azulejo naquela posição especificada.
Será um ipint.
Eu salva isso para ver se está funcionando o negócio aqui, depois da refatorização dos nomes de tijolos para azulejos.
Certo, então sem problemas.
Agora vamos aqui, então vamos retornar dessa função, nós vamos pegar o azulejo, né?
E temos que encontrar o elemento em uma certa posição no mapa.
Vamos supor, por exemplo, que eu estou aqui no mapa, né?
Vamos considerar a linha, a primeira.
Então eu estou aqui na segunda linha.
A posição, a segunda linha agora é y32.
Agora, se eu tivesse aqui embaixo, que quisesse, e mais para baixo, né?
Aperta essa seta para baixo.
Isso é o muro.
Qual seria aquela próxima posição daquele muro?
Seria 0, 32, 64, 96.
Y seria 96, né?
Próxima posição.
Y96 e qual é a linha, né?
O índice dessa linha.
Bem, a terceira é a quarta linha, né?
A próxima, se eu fosse para baixo.
A quarta seria índice 4 menos 1, né?
0, 1, 2, 3.
Linha 3.
Então, olha só o que acontece se você pegar essa posição 96, dividir pelo tamanho do azulejo que é 32,
você pega 3, que é o índice da linha.
Então nós vamos pegar a posição y,
dividir pelo tamanho do azulejo que é 32,
eu vou fazer uma variável aqui, 32.
Eu sei que já tem aqui na linha 94, mas você pode modificar isso depois.
Então isso vai lidar,
vai mapear corretamente nessa array, na posição y, na linha, né?
Agora nos resta fazer a coluna, né?
A posição x.
Mesma coisa, tá?
Nesse caso aqui vamos fazer outro exemplo.
Se eu tivesse aqui, né?
Na segunda linha, a terceira coluna.
Como seria?
Bem, se eu quisesse para a direita, né?
Posição próxima para a direita seria linha, seria no caso do x, né?
0, 32, 64, 96.
Olha só, no x, 96.
Qual é a coluna?
Coluna é a quarta, né?
Então 0, 1, 2, 3.
Mesma coisa, né?
Em vez de que o seu linha é coluna aqui.
Então olha só, 96 dividido por 32, 3, que é o número da coluna.
É a mesma coisa, né?
Só muda a posição que agora é que é x,
dividido pelo tamanho do azulejo que é 32.
Então tá aí.
Isso vai mapear a coordenada, coordenado do próximo coordenado, né?
Para o elemento lá na array de azulejos que contém o id para determinar se é o chão ou é o muro.
Vamos testar essa função aqui, eu vou fazer um log de debug.
Logo na hora que você mudar a posição do jogador,
eu vou fazer um debug para realmente ver se está mapeando corretamente.
Então aqui dentro da função principal,
na hora do event type sdl key down,
depois do if else, if else, if else, if.
Vou fazer um log aqui std, 2 pontos.
2 pontos, cout.
Eu vou dizer id da posição do jogador do azulejo, né?
Do azulejo, a posição do jogador.
Vai ser igual a, eu vou chamar a função mapear, coordenado para id do azulejo.
E vou passar com argumento.
Quem?
Posição do jogador, vígula.
Precisamos da...
do azulejo, né?
Nós temos essa variável aqui em cima, se você se lembra, na linha 124.
É uma array de duas dimensões.
E eu vou botar uma kebra de linha, and L.
Vamos ver se realmente está certo.
E o que é que aconteceu? Um erro aqui.
Ah, eu esqueci do namespace do and L, que é std.
Pronto, agora, se eu mover para a direita,
nós esperamos que o id seja zero.
Vamos ver a mensagem zero.
Se eu ir para baixo, o id é 1, correto.
Para a direita é zero, para a direita é 1, para a direita é 1,
para a direita é zero, para a direita é zero, zero, 1, 1.
Para cima é 1, para a esquerda é 1.
Então está corretamente tudo certo, né?
Agora que a gente já tem essa função, nós precisamos verificar
se a próxima posição vai ser um azulejo atravessável, né?
Eu devo lembrar aquilo que eu escrevi aqui, vamos fazer essa função.
O azulejo for atravessável.
Então vamos ver aqui.
Aqui em cima, vamos fazer outra função,
eu vou chamar a função azulejo for atravessável.
E eu vou passar como o parâmetro aqui vai ser o id do azulejo, tá?
Id do azulejo.
A saída vai ser um boleano, então vai ser bo, verdadeiro ou falso?
Se o id for zero, né?
Se o id do azulejo for zero, o que isso significa?
Que é o chão.
O chão você pode atravessar, então return true.
Se não for zero, né?
Else if, você pode até botar falso aqui,
que se não for zero, será qualquer outro valor, será um, dois, três, sem pudeante.
Mas é bom você fazer o else if aqui,
já antecipando que você sabe que no jogo de verdade tem vários tipos de azulejos.
Alguns são atravessáveis, outros não são.
Então por isso que eu tenho vários else if aqui, vários casos,
já vai adicionar o caso específico do azulejo C1, tá?
Nesse caso será falso.
Agora o else, né?
Ou nem pensei digitar else porque já vai bater aqui no final, então opcional.
Ah, você faz aí, eu vou retornar falso, se não conseguir verificar nenhum id reconhecido, né?
Se não reconhecer nenhum id vai ser falso.
Qualquer id que não é reconhecido não vai ser atravessável.
O id atravessável é o zero que é o do chão, o não atravessável é o do muro ou qualquer outro,
que a gente não definiu até agora.
Então se eu for aqui testar essa função aqui embaixo na hora do log, né?
Eu vou botar a sddsc out atravessável, e eu vou botar o valor aqui.
Eu vou dizer como é o nome.
Azulejo for atravessável.
Eu vou botar, na verdade eu preciso pegar o valor que foi retornado pela função,
mas a pia coordenada, então vou botar uma variável chamada de próximo azulejo, né?
Ou id do próximo azulejo, do próximo azulejo.
Será isso?
E eu vou pegar isso, colo aqui onde estava antes da função.
E se for atravessável eu vou passar o id do próximo azulejo, e vou quebrar um linha aqui, sddsc 2 pontos 2 pontos, and L.
Vamos testar isso novamente.
Eu vou andar para a direita, id da posição dos jogadores, o id desse azulejo que eu estou agora é zero, está correto.
O chão é atravessável, um, um significa true, certo? Zero é false.
Então eu vou para baixo agora.
Atravessável não, zero.
Travessável sim, para a direita não, não, zero.
Para baixo sim, para baixo não, não, não é tipo diante.
Então está corretamente implementado.
Agora vamos modificar só um pouquinho essa função para poder usar o chamado INAM.
Vamos criar esse INAM aqui, tipo de azulejo, chão, muro.
Para poder a gente notar que digitar valores numéricos inteiros, porque é difícil para o programador entender o que está acontecendo.
O que é que é zero? Sempre tem que ficar procurando tabela de mapeamento.
A zero é o chão, a um é o muro.
Então para poder ter que fazer isso nós podemos substituir esse valor com uma enumeração.
Você pode criar aqui, posso até botar aqui antes, ou lá em cima.
INAM, vou botar aqui no scopo global para poder usar em outros cantos.
Vamos falar tipo de azulejo.
Vai ser o que? Tem o chão e tem o muro.
Ele começa contando zero, então o chão é zero, o próximo muro é um.
Então na hora que você passar azulejo para o atravessado você pode checar em vez de zero aqui.
Você põe a chão em vez de muro, em vez de um, você põe muro.
E na sua verificação funcionou.
O que é que aconteceu?
Muio 91. Ah, eu acho que eu esqueci do ponto em vírgula.
Eu tinha esquecido do ponto em vírgula na linha 94.
Traveçável, então tudo certo como antes.
Você pode até modificar esse variável que o tipo pode até ser o tipo do INAM, o tipo de azulejo.
Também funciona, né?
Nesse caso, infelonciment, conversion, int, tipo de azulejo.
Você teria que converter na hora que de... Cadê?
De fazer...
Mapir a coordenada teria que converter, né?
Poderia você modificar isso para converter para tipo de azulejo.
Mas ou pode ser na chamada da função, também, cadê a chamada?
Posso converter aqui para tipo de azulejo?
Ah, deixa assim mesmo, tá?
Tá bom, assim.
Outro detalhe, se você quiser seguir a C++11, você pode botar INAM CLASS.
Dessa maneira, você pode dar uma scop aqui para ativo de azulejo, 2 pontos, 2 pontos.
Para não ter que ter essa variável, esteja um em muro independente.
Pode fazer isso também.
Ah, o que aconteceu?
INAM CLASS.
Eu acho que tem que fazer o...
O ID do azulejo tem que ser do tipo de azulejo para isso funcionar.
Eu tenho que fazer o casting aqui.
Então, seria que teria que pegar algo para estar aqui.
Aí, a chamada estaria errada também.
Não pode converter IN, tipo, para o tipo, teria que converter lá.
Enfim, eu deixo como é o exercício para você modificar a sua maneira aí.
Tá bom?
Não ser problemas.
Então, vamos continuar e fazer a implementação da colisão aqui.
Já temos o debug, depois vamos revolver isso, tá?
Deixa aí só para debugar.
Então, na hora das posições aqui, vamos checar o ID do próximo azulejo e tal e tal.
Então, vamos fazer o seguinte, vamos começar indo para direito.
Se eu for para direita, né?
E se estiver ainda na tela, vou fazer o seguinte.
Vou criar um SDL-REC para fazer a nova posição.
E vou copiar os valores de posição jogador.
Agora, pega a nova posição.
O X vai adicionar 32, que está em para direita.
Você vai pegar essa nova posição e passar para o map.a coordenada para o ID do azulejo.
Então, azulejos.
Isso vai ser o ID do próximo azulejo.
Aí você vai checar.
Se o ID do próximo azulejo for atravessável, né?
Azulejo for atravessável.
Você muda a posição.
Se tu é, você vai deixar fazer a posição jogador X, posição jogador X mais 32.
Vamos testar.
Direita, direita, direita, direita, direita, não dá.
Para baixo, para baixo, direita, direita, direita, direita, não dá.
Para cima, direita, direita, direita, direita, não vai para direita, tá?
Tá certo, então.
Mesma coisa para as outras posições.
Se você quiser pausar o vídeo, tentar fazer para o si próprio.
E a gente vai continuar na mesma padrão.
Então, vamos lá.
Para poder fazer indo para baixo, cria um SDR-RECT para a nova posição.
Copie a usuária de posição jogador, igual a posição jogador.
Agora você pega a nova posição.
Nesse caso indo para baixo é o Y, ponto Y mais 32, mais igual a 32.
Então, pega o ID do próximo azulejo.
O próximo azulejo é igual a mapear a coordenada para o ID do azulejo da nova posição e azulejos.
Se o azulejo for atravessável, o ID do próximo azulejo,
você deixa ele mudar de posição sem problemas.
Vamos testar.
Vindo para baixo, baixo, não dá.
Para baixo, baixo, não dá.
A baixo, baixo, não dá.
A baixo, não dá.
Mesma coisa para a esquerda e para o direito.
Vou copiar e colar porque é a mesma coisa.
Deixa eu ver aqui em cima.
Dentro do F, cola na nova posição, indo para a esquerda,
vai ser X menos 32, menos igual a 32.
O próximo azulejo na nova posição, azulejos for atravessável e o do próximo azulejo.
Dentro vai ser a posição X menos 32 do jogador.
Salvar.
Vamos tentar.
I para a esquerda, não vai.
A esquerda ali, não vai.
Para a esquerda ali, não vai.
Certo?
Direita, não vai, a esquerda não vai.
Para baixo, não vai.
Vamos fazer para cima, mesma coisa.
Vou copiar e colar.
Dentro do F, nova posição, posição do jogador.
Indo para cima é Y mais 32,
ID do próximo azulejo, int, mapear para o coordinado na nova posição.
Azulejo, se o azulejo for atravessável, você vai pegar a posição X
e realmente do jogador e tirar 32.
Compilar e rodar.
Vamos lá, tentar ir para cima.
Para cima não dá, para cima não dá, para cima não dá.
Então, cobrimos todas as direções.
Para a esquerda, para a direita, para baixo, para cima.
O muro agora não pode atravessar, está bloqueando a gente.
Vamos ter um código repetido, nós podemos fazer uma repatorização.
Por exemplo, sempre tem SdlE-REC,
SdlE-REC, eu posso extrair esse SdlE-REC para nova posição,
para fora,
para todos, antes do F.
Então, posso tirar para fora.
Tira aqui, linha 175, tira, já está definindo lá fora.
Linha 184 também está definindo lá fora.
Certo?
Vamos pegar extrair agora, pegar isso tudo aqui.
Dentro do key down,
eu vou fazer uma função, vou chamar de processar a entrada do jogador.
Processar a entrada do jogador, vou chamar essa função,
vamos criar lá em cima.
Processar a entrada do jogador, essa função vou colar aqui do que a gente já tinha.
Para poder funcionar, precisamos de key parameters.
Posição do jogador, né?
Jogador, isso é do tipo SdlE-REC.
Como a gente está modificando aqui na linha 115, vamos dar referência.
Vamos passar lá como referência, vou botar o 1%.
Para ele modificar o valor, quando a gente modificar nessa função,
também vai modificar lá fora.
Naquele que chama a função, o scopo vai também ser modificado.
Precisamos de o que mais? Bem, evento.
Vamos pegar o evento também, vou falar SdlE-Event.
Como a gente não modifica o evento, vou deixar assim, para passar para o valor.
A processar a entrada do jogador não retorna nada, vou falar void como valor de retorno.
Vamos ver se funciona assim.
A gente tem que modificar a chamada.
Vá na chamada da função, passa o event e passa a posição do jogador.
E... Ah, também tem que passar o quê?
Azulejos.
Então tem que passar os azulejos, vai ser uma rede duas dimensões, 15 e 20.
Vamos lá, como terceiro, o parâmetro da função para acessar a entrada do jogador.
Azulejos, o tipo vai ser int, antes int azulejos, o shet 15 com shet 20.
E agora, o que é que eu fiz? Errado.
Na função, posição do jogador não foi...
Eu botei do jogador, é posição do jogador.
E o outro vai ser erro, linha 111, pausando a constante.
Eu vou pegar esses constantes de WindowWidth, WindowHeight.
E vou botar lá no escopo global.
Vou aproveitar também pegar o tamanho do azulejo, vou botar no escopo global.
Vou lá em cima.
E vou botar aqui em cima.
Agora ele vai funcionar sem problemas.
Tá bom?
Vamos recapitular o que a gente fez.
Implementamos a colisão com o muro.
Temos o mapa do jogo com cada elemento, isso é representado nesse arquivo de texto.
E nós armazenamos isso em uma array de duas dimensões, linhas e colunas.
Cada elemento tem o inteiro, que é o id do azulejo, zero sendo o chão, um sendo o muro.
Fizemos uma função para mapear as coordenadas x e y, que o jogador iria se mover.
Mover para.
E mapeamos isso com a função mapear a coordenada para id do azulejo.
Função que pega essa próxima posição, S-T-L-E-R-E-T,
pega aquele mapa dos azulejos e mapei a posição para o id usando essa forma.
A linha será de índice e posição y dividido pelo tamanho do azulejo, que é 32.
O coluna seria a posição x dividido pelo tamanho do azulejo, que é também 32.
Notes que estão usando o azulejo depois, diferentes na horizontal e vertical, é só modificar essas variáveis aqui.
Criamos esse enam para a gente falar chão e muro, em vez de zero e um.
Fica mais legal, deixe como exercício se você quiser fazer aquela enam class, para você fazer o escopo do enam.
Para ele não ficar assim sem escopo de tipo de azulejo dos pontos.
Essa função azulejo foi atravessável, pega o id do azulejo e diz, sim ou não, esse azulejo você pode andar.
Se o id for zero, isto é chão, true, e for um, é muro, false.
Se for qualquer outro id que a gente não tem definido, ainda nesse jogo, vai ser não atravessável, false.
Finalmente, refatorizamos tudo nessa função para acessar a entrada do jogador.
Na hora que o jogador bate a tecla lá, cima, direita, para baixo, para esquerda, ele vai verificar, antes de modificar a posição,
verifica se a nova posição, a gente cria nova posição, adiciona para vai lá na nova posição e verifica se o id desse azulejo é atravessável.
Se for o caso, ele vai deixar o cara passar.
Finalmente, eu vou remover essa mensagem do bug, que é a gente verificar se a função está funcionando corretamente.
Então, com isso, por essa aula é só, pessoal, por favor, eu se apoio aí.
Se você gostou do vídeo, deixe o comentário.
Não se esqueça de escrever e até a próxima.
Nenhum comentário ainda (loading...)
Nenhum comentário ainda (loading...)
Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: