Resposta do retângulo de colisão

10

Estou tendo dificuldades em obter um retângulo móvel para colidir com mais de um retângulo.

Estou usando SFML e tem uma função útil chamada intersectsque leva 2 retângulos e retorna as interseções. Eu tenho um vetor cheio de retângulos que eu quero que meu retângulo móvel colide. Estou percorrendo isso usando o seguinte código (p é o retângulo móvel).

IsCollidingWithretorna um bool, mas também usa SFML intersectspara calcular as interseções.

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

e o Collide()código real :

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

e o IsCollidingWith()código é:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

Isso funciona bem quando há apenas 1 Rectna cena. No entanto, quando há mais de um Rect, causa um problema ao resolver duas colisões de uma só vez.

Alguma idéia de como lidar com isso corretamente? Fiz upload de um vídeo no youtube para mostrar meu problema. O console na extrema direita mostra a largura e a altura das interseções. Você pode ver no console que está tentando calcular duas colisões de uma só vez, acho que é aqui que o problema está sendo causado.

Finalmente, a imagem abaixo parece ilustrar bem o meu problema:

retângulo colidindo com vários outros retângulos

dotty
fonte
O link do vídeo está quebrado.
XiaoChuan Yu
Os colliderobjetos retornados são this->getCollider()atualizados por this->move()??
XiaoChuan Yu
Você poderia adicionar mais algumas informações, por favor? Qual é exatamente o problema? O vídeo do YouTube parece mostrar um comportamento previsível, e há apenas um outro retângulo na cena.
Wackidev 02/06

Respostas:

3

Sua imagem ilustra um dos muitos problemas ao tentar usar formas convexas - particularmente retângulos - para simular uma superfície plana como um piso. O algoritmo leva os caracteres a ficarem presos nas bordas internas das formas que compõem o chão.

Uma correção simples é verificar apenas a colisão vertical, corrigir isso e verificar novamente a colisão horizontal. A menos que você esteja caindo e tentando deslizar por uma parede, nesse caso, você deseja verificar primeiro as colisões horizontais. Como você sabe quando verificar qual primeiro? Você pode fazer isso com base em qual componente da sua velocidade é maior (se o movimento horizontal for maior, verifique primeiro as colisões verticais, caso contrário, verifique as colisões horizontais).

O que pode ser ainda mais simples - e com melhor desempenho - é gerar uma lista de arestas para o seu mundo. Ou seja, para as caixas que formam o piso, defina uma bandeira indicando que apenas a borda superior é realmente colidível e depois ignore colisões com as outras bordas. Você não poderá usar a rotina de colisão do SFML para isso, mas honestamente, simplesmente colisões de caixas são possivelmente o código mais fácil que você já escreveu em um jogo. Essa técnica funciona particularmente bem se o seu mundo estiver alinhado a uma grade. Gostaria de verificar os excelentes tutoriais do Metanet (http://www.metanetsoftware.com/technique.html/) para essa técnica.

Você vai encontrar muitos outros problemas tentando criar um jogo de plataforma 2D simples como você. De longe, o melhor recurso que já vi para o latel é o seguinte, que você deve ler e depois ler novamente:

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

Sean Middleditch
fonte
1

Talvez uma solução simples seja verificar colisões com todos os retângulos e recuar, na direção oposta do movimento, até que nenhuma colisão seja detectada. Se isso resolver o problema, a implementação também deve ser bastante simples.

arex
fonte
+1, eu realmente escrevi sobre isso aqui: gamedev.stackexchange.com/questions/38252/…
Markus von Broady
0

Não acho que ter 2 colisões calculadas seja um problema, apenas uma questão de desempenho. Para que a colisão seja tratada corretamente, pode ser necessário testá-lo duas vezes. Usando seu diagrama, pense se A for testado contra B primeiro, ele também precisará ser testado com as outras caixas e poderá colidir com outra.

Espero que seja útil?

james82345
fonte
0

Na verdade, esse não é um método ideal; você deve tentar determinar o mais cedo possível quando ou o primeiro ponto ao longo do caminho dos objetos em movimento onde ocorrem colisões e mover os objetos para essa posição (ou a posição no tempo calculado), tentando corrigir com base nas posições penetrantes após o movimento é muito problemático, mas você pode usar seu processo atual com uma pequena alteração. Continue verificando colisões até que não haja nenhuma.

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

Observe que há situações em que isso levará a um loop infinito (pense em uma situação em que mover a caixa de uma colisão resulta em outra coleção e mover a caixa dessa colisão a move de volta para a mesma posição de colisão de antes)

Matthew R
fonte