Como lidar com colisões de canto em 2D?


22

Estou escrevendo um jogo XNA de cima para baixo em 2D. Desde o meu primeiro, estou tentando escrever as coisas da física e da colisão para aprender.

Sempre que meu personagem sprite de jogador tenta se mover para uma posição em que seus limites se cruzam com a borda de uma parede, descubro um ângulo de rebatimento (ângulo de incidência = ângulo de reflexão) e faço o jogador saltar da parede e evitar a colisão .

Estou tendo problemas para descobrir como lidar com a situação do meu sprite se cruzando com duas arestas da parede simultaneamente, por exemplo, quando atinge um canto.

colisão de canto

Atualmente, meu código me diz que duas arestas da parede foram cruzadas, mas não em qual aresta ele teria atingido primeiro e, portanto, em que aresta ricochetear.

Qual é o teste matemático para escolher qual borda rebater? É fácil ver quando olhamos para ele, mas estou lutando para descobrir o teste de matemática para ele.



Obrigado Tetrad. Eu vi esse, mas parecia que a bola se comportaria de maneira diferente do meu problema retangular. No caso ilustrado acima, o sprite retangular teria atingido a borda inferior da parede e ricocheteado nela. A borda lateral da parede nunca teria entrado na equação. Só não sei como expressar isso em código e tomar essa decisão.
TerryB 21/09

Respostas:


9

Se você calcular o quão longe no Wallo Player Spritemudou, você provavelmente pode baseá-lo no delta do x e y coordenadas dos cantos que estão se cruzam. Espero que faça sentido, não consigo pensar em uma maneira melhor de expressar isso.

Então, por exemplo, se você olhar para o seu diagrama. Pegue o xvalor do canto superior esquerdo do Player Sprite(após a movimentação) e subtraia o xvalor do canto inferior direito do Wall. Faça o mesmo para os yvalores e depois veja qual é maior. A chave é que, se um é maior que o outro, o Player Spriteprovavelmente se cruza nesse lado.

Aqui está um exemplo de imagem (esta é uma subseção da sua imagem com minhas próprias linhas adicionadas):

exemplo de interseção

Agora, você vê aqui que a linha azul é maior que a linha verde. Nesse caso, a linha azul também está do lado em que Player Spritese espera que ela salte.

Se os dois valores forem iguais, eles acertam na esquina.

Agora, há um pequeno problema em fazê-lo dessa maneira. Se o Player Spriteveículo estiver viajando muito rápido ou a colisão estiver muito próxima da esquina, é possível que ele Player Spriteavance mais na Walldireção errada. Nesse caso, você provavelmente terá que verificar a velocidade do objeto em movimento. (Veja a resposta de Nathan Reed .)

Nota: Acho que estou essencialmente tentando descrever a detecção de colisão SAT mencionada pelo @Blau, mas passei muito tempo escrevendo isso, então vou publicá-la de qualquer maneira. Espero que ajude você.


Obrigado Drackir! E acho que se minha parede for girada em relação ao sprite, é um pouco mais complicada, mas o mesmo princípio se aplica. Procure o vetor de deslocamento de comprimento mínimo que significaria que o sprite não colidiria com a parede. Em seguida, use a parede que é normal para esse vetor como a minha para saltar.
precisa saber é o seguinte

@TerryB - A rotação adiciona um pouco mais de complexidade a ela. Você pode ler as caixas delimitadoras alinhadas ao eixo (AABB). Basicamente, você ainda usa o mesmo princípio acima testando a menor caixa na qual o objeto girado se encaixará, mas cujos eixos estão alinhados aos eixos cartesianos. Imagine se você tivesse um quadrado e o girasse 45 graus para torná-lo um diamante. Calcular a colisão com isso seria difícil e dispendioso; portanto, verifique primeiro se o objeto está próximo usando o AABB, que seria um quadrado onde cada ponto do diamante toca cada lado do meio.
Richard Marskell - Drackir

Então, quando você souber que está próximo, pode fazer os cálculos mais caros para ver se eles se cruzam em ângulos (o que provavelmente deve ser outra questão :)).
Richard Marskell - Drackir

1
-1, pois o deslocamento mínimo nem sempre dá a resposta correta para "qual borda colidiu primeiro"; veja minha resposta.
Nathan Reed

@ NathanReed - É por isso que mencionei verificar a velocidade no meu parágrafo "Agora, há um pequeno problema em fazê-lo dessa maneira".
Richard Marskell - Drackir

15

O deslocamento mínimo nem sempre fornece a resposta certa para qual borda foi atingida primeiro. Considere este caso:

caso que quebra o algoritmo de deslocamento mais curto

Isso acontece quando a velocidade é alta o suficiente para que o bloco se mova bastante longe durante um quadro. Para detectar corretamente qual aresta foi atingida primeiro, você precisará configurar uma equação linear para resolver o tempo de colisão com cada aresta. Nesse caso, descrito no diagrama do OP, as equações relevantes são:

timeXCollision = (player.left - wall.right) / -player.velocity.x
timeYCollision = (wall.bottom - player.top) / player.velocity.y

(Isso pressupõe um sistema de coordenadas X-direita e Y-up.) Em geral, você teria que usar os sinais dos componentes X e Y de player.velocity para determinar qual par de arestas precisa ser testado. De qualquer forma, depois de calcular os tempos de colisão, a mais antiga das duas é a colisão que você precisa lidar.


1
Você poderia fornecer um exemplo de como suas duas variáveis ​​poderiam ser implementadas?
BjarkeCK

1

Você precisa da detecção de colisão SAT

Basicamente, você precisa procurar o vetor de deslocamento mínimo que é subtraído a um dos objetos, para que eles não se cruzem.

Na sua imagem, o deslocamento mínimo é o segmento laranja.

insira a descrição da imagem aqui


4
-1, pois o deslocamento mínimo nem sempre dá a resposta correta para "qual borda colidiu primeiro"; veja minha resposta.
Nathan Reed

quem está perguntando isso?
Blau

A pergunta está perguntando isso. "Atualmente, meu código me diz que duas arestas da parede foram cruzadas, mas não em qual aresta seria atingida primeiro e, portanto, em que aresta ricochetear".
Nathan Reed

primeiro? o problema não é o primeiro, ele colide com as duas arestas ao mesmo tempo, ... a questão é qual aresta ricochetear, você escolheu um método que é bom para você, eu escolhi um método que seja bom para mim, ambos são válidos
Blau

1
Se você deseja tomar uma decisão de design para deixar objetos passarem um pelo outro dessa maneira, como se fossem arredondados ou chanfrados nos cantos, essa é sua decisão e pode ser a coisa certa para a sua jogabilidade. Mas não acho que a pergunta seja sobre uma decisão de design; está perguntando matematicamente como saltar retângulos alinhados por eixos. Isto não é uma questão de interpretação; esse problema de matemática tem uma resposta clara e correta para qual margem ricochetear.
Nathan Reed

0

Respondeu a uma pergunta semelhante aqui

Você pode considerar verificar posições anteriores -

Por exemplo: se seu lado esquerdo estava anteriormente à direita do lado direito e você está colidindo, ocorreu uma colisão com a mão direita.

Se você fizer isso, resolva as colisões do eixo y, verifique se está colidindo com alguma coisa e, em seguida, resolva as colisões do eixo x.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.