Classe de colisão de cima para baixo reutilizável


8

Recentemente, peguei o monogame e estou trabalhando em um jogo simples de cima para baixo para começar e aprender o básico.
Eu tenho o movimento e a rotação para seguir o mouse, mas estou preso às colisões.
O que eu quero saber, basicamente, são duas coisas:

  1. Qual seria a melhor maneira de lidar com colisões? Eu sei que Rectangle.Intersects(Rectangle1, Rectangle2)retorna o retângulo sobreposto, mas, como o movimento de cima para baixo está no eixo x / y, eu gostaria de saber onde a colisão está acontecendo, para que eu possa criar um tipo de "deslizamento de parede" onde o jogador não consegue preso na parede.
    Verificar as coordenadas x / y dos jogadores em relação às coordenadas de objetos sólidos e depois jogar o jogador na posição anterior se ele entrar nos limites de um objeto sólido é realmente a melhor abordagem? O que você sugeriria?
  2. Qual seria a melhor maneira de aplicar colisões a todos os sólidos, npc's etc.? Atualmente, estou pensando em criar uma gameObjectclasse da qual todos os objetos herdarão e manipularão as colisões ali.

Obrigado pela leitura e espero que alguém possa me dar algumas dicas.


Para refletir sobre sua segunda pergunta, dê uma olhada nesta resposta sobre arquitetura de jogos .
Andrew Russell

Respostas:


9

Geralmente, a maneira como a maioria dos mecanismos de física lida com esse problema é separando os objetos que se cruzam .


Portanto, se seus objetos são representados por retângulos (também conhecidos como "Caixas delimitadoras de eixos alinhados") e colidem em um determinado quadro da seguinte forma:

Colisão


Você mede a quantidade de interpenetração em cada eixo. Em seguida, selecione o eixo com a menor quantidade de interpenetração e separe os objetos ao longo desse eixo.

Separado


Você então registraria isso como uma "colisão" e aplicaria a dinâmica apropriada.

Por exemplo, se você quiser deslizar ao longo da parede, zeraria a velocidade no eixo que separou (o eixo X, na ilustração acima), deixando a velocidade no outro eixo sozinha.

Mas você também pode aplicar fricção ou fazer com que os objetos se separem.


Aqui está um excelente tutorial interativo que mostra como fazer isso com muito mais detalhes.

Embora, se você estiver indo muito longe nesse caminho (algo mais do que simples colisões AABB), convém considerar o uso de um mecanismo existente como o Farseer Physics .


Finalmente, uma observação sobre a implementação (se você não seguir a rota Farseer): Rectangleusa intvalores, que na verdade não são apropriados para fazer física na maioria dos casos. Considere criar sua própria AABBclasse que usa em seu floatlugar.

Sua segunda pergunta é muito bem respondida pela minha antiga resposta sobre arquitetura de jogos aqui , então não vou repeti-la aqui.


Talvez haja algo que eu não entenda, mas essa abordagem não é falha? Eu ilustrei o problema aqui: jmp.sh/jEW2lvR Isso resultaria em algum comportamento estranho às vezes.
BjarkeCK

@BjarkeCK: Sim, você precisa fazer um trabalho extra para lidar com casos como esse. Eu não sou bem versado o suficiente para explicar completamente como lidar com eles adequadamente (eu apenas uso Farseer e chamo de dia). Possivelmente, dê uma olhada na "Seção 5" deste link .
Andrew Russell

1

1: Também estou trabalhando em um jogo de ação de cima para baixo relativamente simples e, depois de uma semana (-s?) De luta, acabei usando um tipo de abordagem passo a passo para detecção e resposta a colisões. A principal razão é que o uso da menor quantidade de interpenetração resultaria em alguns casos em "teletransporte" para uma nova posição na qual o objeto em movimento não estava anteriormente.

então, quando um objeto quer se mover,

  1. Eu crio uma caixa delimitadora do objeto na posição do objeto + vetor moveAmount, criando uma espécie de caixa delimitadora de destino
  2. então eu checo esta caixa delimitadora de alvo para qualquer interseção com os objetos do jogo, peças, etc. Se houver, eu os adiciono a uma nova lista, que contém todas as possíveis colisões para o quadro atual
  3. se não houver interseções, o objeto se move. mas se houver um cruzamento,
  4. Dividi o movimento desejado em "etapas". então eu corro um loop para o número de etapas que tenho. cada etapa move o objeto apenas por 1 pixel nas direções x e y.
  5. para cada etapa, verifico cada nova posição projetada em busca de colisões; se nada, adiciono o vetor de movimento da etapa ao vetor de movimento final.
  6. se houver uma colisão (interseção retorna verdadeiro), comparo a posição anterior (posição na etapa anterior) do objeto em movimento com a coisa com a qual ele está colidindo.
  7. dependendo desta posição anterior, interrompo o movimento ao longo do eixo conflitante (por exemplo, se o objeto em movimento chegar ao objeto colidindo por cima, defino o valor de y do vetor de movimento como 0 etc.).
  8. Repito isso para cada etapa consecutiva, adicionando os vetores de etapa ajustados para fazer um vetor moveAmount final ajustado que posso usar com segurança para mover o objeto sem que ocorram colisões.

Essa abordagem garante que o objeto "volte" para a posição anterior correta e permite deslizar contra as paredes, objetos, o que for.

2: Eu próprio uso uma classe de colisão estática que pode ser usada por qualquer que seja. possui métodos de detecção de colisão e ajuste de vetor, que podem ser chamados por praticamente qualquer coisa. se esses métodos são chamados de uma classe de jogo "mestre" ou por alguma subclasse de objeto não importa realmente no meu caso, porque a classe de colisão cria uma nova lista a cada quadro para todos os retângulos com os quais o objeto em movimento está cruzando. esses retângulos podem ser de ladrilhos, decorações, NPCs, o que quer que tenha limites e seja colidível, basicamente. isso significa que a necessidade básica de todos os objetos do jogo que sejam colidíveis é ter um retângulo de limites. se eles tiverem isso, a classe de colisão cuidará do resto.

espero que isso seja compreensível.


0

1: Utilizei com sucesso uma técnica para resolver isso: usando a velocidade e a posição, você pode descobrir a colisão e iterar de volta até que a posição esteja muito próxima do ponto exato de colisão.

Isso não faz parte da resposta da sua primeira pergunta, mas se você tiver muitos objetos que podem colidir entre si, use quadtrees para melhorar o desempenho. Há um tutorial muito bom com muitos exemplos aqui .

2: eu sempre recomendo sistemas de entidades .

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.