Atualmente, tenho um jogo de plataformas com ladrilhos para o terreno (gráficos emprestados do Cave Story). O jogo foi escrito do zero usando XNA, então não estou usando um mecanismo existente ou físico.
As colisões de lado a lado são descritas exatamente como descrito nesta resposta (com SAT simples para retângulos e círculos), e tudo funciona bem.
Exceto quando o jogador colide com uma parede enquanto cai / pula. Nesse caso, eles pegam um ladrilho e começam a pensar que atingiram um piso ou teto que não está realmente lá.
Nesta captura de tela, o jogador está se movendo para a direita e caindo para baixo. Então, após o movimento, as colisões são verificadas - e primeiro, o personagem do jogador está colidindo com a peça 3 do chão e empurrada para cima. Segundo, ele descobriu que estava colidindo com o ladrilho ao lado dele e empurrado para o lado - o resultado final é que o personagem do jogador pensa que está no chão e não está caindo, e 'pega' o ladrilho enquanto ele o encontra. .
Eu poderia resolver isso definindo os ladrilhos de cima para baixo, o que o faz cair suavemente, mas o caso inverso acontece e ele atinge um teto que não existe quando se pula contra a parede.
Como devo abordar a resolução disso, para que o personagem do jogador possa cair ao longo da parede como deveria?
fonte
Respostas:
A abordagem mais simples e à prova de falhas é simplesmente não verificar colisões nas arestas ocultas. Se você tiver dois ladrilhos de parede, um diretamente acima do outro, a borda inferior do ladrilho superior e a borda superior do ladrilho inferior não devem ser verificadas quanto à colisão contra o jogador.
Você pode determinar quais arestas são válidas durante uma passagem simples sobre o mapa de blocos, armazenando arestas externas como sinalizadores em cada local de bloco. Você também pode fazer isso em tempo de execução verificando blocos adjacentes durante a detecção de colisão.
Existem versões mais avançadas dessa mesma técnica que facilitam e agilizam o suporte a blocos não quadrados também.
Eu recomendo que você leia os artigos abaixo. São apresentações simples decentes para fazer física básica e detecção de colisão em plataformas modernas (como Cave Story). Se você quer um Mario mais antigo, há mais alguns truques com os quais se preocupar, mas a maioria envolve lidar com saltos e animações, em vez de colisão.
http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html
fonte
Aqui a ordem que eu faria as coisas ....
1) Salvar atual X, Y do caractere
2) Mova a direção X
3) Verifique todos os cantos do caractere, obtendo os dados do bloco e verifique se são sólidos, fazendo o seguinte: (X e Y são a posição do caractere)
... para obter dados corretos do bloco a partir dos dados do mapa
4) Se qualquer um dos blocos for sólido, será necessário forçar X para a melhor posição possível restaurando o X salvo e ...
5) Repita 2-4 usando Y
Se seu personagem for mais alto que um ladrilho, você precisará verificar mais ladrilhos. Para fazer isso, você precisa fazer um loop e adicionar tileHeight à posição characterY para obter o tile
Se o caractere for maior que 1 bloco, faça o mesmo, mas substitua characterY, characterHeight, tileHeight, etc por characterX, characterWidth, etc
fonte
E se você verificasse a possibilidade de uma colisão como parte do método de movimento do jogador e rejeitasse o movimento que fazia o jogador deslizar para outro objeto? Isso impediria o jogador de "entrar" em um bloco e, portanto, ele não poderia estar "em cima" do bloco abaixo dele.
fonte
Encontrei quase exatamente o mesmo problema em um jogo em que estou trabalhando atualmente. A maneira como resolvi foi armazenar a área da parte sobreposta ao testar colisões e, em seguida, lidar com essas colisões com base em sua prioridade (maior área primeiro), depois verificar duas vezes cada colisão para ver se ela já havia sido resolvida por uma anterior. tratamento.
No seu exemplo, a área da colisão do eixo x seria maior que o eixo y, portanto seria tratada primeiro. Antes de tentar lidar com a colisão do eixo y, ele verificaria e não veria mais colisão após ser movido no eixo x. :)
fonte
Uma solução simples, mas não perfeita, é alterar a forma da caixa de colisão do jogador para que não fique quadrada. Corte os cantos para torná-lo semelhante ao octógono ou algo semelhante. Dessa forma, quando ele colide com um azulejo como os da parede, ele desliza para fora e não é pego. Isso não é perfeito, porque você ainda pode notá-lo pegando um pouco nas curvas, mas ele não fica preso e é muito fácil de implementar.
fonte
Um problema muito semelhante foi abordado neste tutorial: Introdução ao desenvolvimento de jogos . A parte relevante do vídeo é às 1:44 , explicando com diagramas e trechos de código.
O aviso 14-tilemap.py exibe o problema de recorte, mas é corrigido em 15-blocker-sides.py
Não sei explicar exatamente por que o último exemplo de tutorial não é cortado enquanto o código é, mas acho que tem algo a ver com:
self.resting
membro no código é usado apenas para verificar se o jogador pode pular. Apesar disso, não consigo fazer um pulo 'duplo' de uma parede. Teoricamente, porém, é possível)fonte
Outro método (ao qual eu respondi a pergunta relacionada ao Byte56) seria verificar se a resolução de colisão coloca o personagem em um local vazio ou não. Portanto, no seu problema, você colide com o teto do retângulo interno para movê-lo para cima, o que seria ilegal (pois você ainda está em colisão com outro bloco). Em vez disso, você só o move se for movido para um espaço livre (como a colisão do bloco superior o moveria para a esquerda) e, depois de encontrar essa colisão, estará pronto.
A resposta que eu dei tinha código, mas ficou muito complicado. Acompanharia todas as colisões dentro desse prazo e levaria apenas a que levasse a um espaço livre. No entanto, se não houvesse, acho que tentei redefinir a posição do personagem para sua última posição, no entanto, isso é realmente feio e talvez você prefira implementar algo como o Mario original, onde ele apenas se move em uma direção ou algo quando não há resolução de espaço livre é possível. Além disso, você pode classificar a lista de resoluções de colisão e mover apenas para o espaço livre com a menor distância (acho que a solução seria a mais preferível, embora não tenha codificado para isso).
fonte
Eu só fiz3 SAT em 3D, então talvez eu não esteja entendendo direito. Se eu entendi o seu problema, isso pode ter ocorrido devido ao contato com um eixo de contato que não deveria ser possível, resultando no jogador agindo como se houvesse um piso. Uma solução alternativa talvez seja usar uma forma de círculo para o seu personagem, então você só terá eixos de contato na direção do eixo x ao bater em uma parede.
fonte