Preso na parede após colisão de caixa delimitadora de retângulo

7

Usando o XNA incorporado no Intersects () em dois retângulos, posso detectar uma colisão e definir minha velocidade como zero. No entanto, o objeto está preso lá e não pode sair! Como posso resolver essa colisão corretamente?

Jopo
fonte

Respostas:

12

Isso ocorre porque, quando seu objeto entra na parede e você encontra a colisão, você está simplesmente parando o movimento do objeto, definindo sua velocidade como zero, mas o objeto ainda está dentro dessa parede.

Para corrigi-lo, você deve resolver a colisão movendo o objeto. Você tem duas opções aqui:

  • Mova o objeto de volta à sua posição antiga, aplicando o oposto da velocidade para cancelar o movimento assim que detectar uma colisão. Prós: extremamente fácil de implementar. Se isso não afetar o seu jogo, escolha esta opção. Contras: Isso impedirá que o objeto se mova em qualquer direção que possa causar uma colisão (para que você não possa deslizar ao longo de uma parede, por exemplo).
  • Encontre de onde o objeto está e resolva a colisão de acordo. Por exemplo, se o objeto vier da esquerda e colidir no lado esquerdo da parede, você simplesmente moverá o objeto para a esquerda da parede. Repetindo isso para todos os lados dos retângulos, o objeto poderia continuar se movendo em direção à velocidade desejada, mas evitaria colisões.

Implementação da segunda opção

Aqui, assumirei que a velocidade representa a direção em que o objeto está indo (basicamente, você não está alterando a velocidade entre a mudança de posição do objeto e a verificação de colisão). Também assumirei que sua origem está posicionada na parte superior esquerda da imagem (portanto, ao mover o objeto para resolver a colisão, posicionarei o canto superior esquerdo).

Aqui está como eu faria:

if (objRect.Intersects(wallRect)) // If there is a collision
{
    Vector2 newPos = obj.Position;

    if (obj.Velocity.X > 0) // object came from the left
        newPos.X = wallRect.Left - objRect.Width;
    else if (obj.Velocity.X < 0) // object came from the right
        newPos.X = wallRect.Right;
    if (obj.Velocity.Y > 0) // object came from the top
        newPos.Y = wallRect.Top - objRect.Height;
    else if (obj.Velocity.Y < 0) // object came from the bottom
        newPos.Y = wallRect.Bottom;

    obj.Position = newPos;
}

Você também pode usar a posição do objeto antigo para descobrir de onde ele é, mas usar a velocidade é mais simples nesse caso.

Jesse Emond
fonte
Ok, então basicamente ele está preso na parede e a colisão continua. Como eu resolveria isso?
Jopo
Estava editando como você pediu. Deseja que alguns exemplos de código mostrem como as duas opções seriam implementadas?
perfil completo de Jesse Emond
Eu tentei implementar o primeiro anteriormente implementando um vetor chamado de direção que é um vetor normalizado com a esquerda ou a direita, dependendo da tecla pressionada, e multipliquei isso pela velocidade em que a colisão foi detectada. Isso funcionou na maior parte, mas parece funcionar apenas em um lado do retângulo (o lado direito?). Para o segundo, eu apreciaria muito um exemplo de código, pois ouvi muito sobre isso, mas não vi implementações concretas.
Jopo
11
Sua primeira opção deve ser um exemplo do que não fazer. Qualquer jogo com esse tipo de detecção de colisão, consideraria defeituoso.
AttackingHobo
11
Por que essa resposta não é aceita se você conseguiu implementar o método fornecido e funcionou?
Jonathan Connell
1

Você pode fazer isso de várias maneiras.

Um método é armazenar a posição anterior do retângulo em cada quadro. Portanto, quando seus retângulos se cruzarem, basta definir a posição do objeto para a anterior que não colidiu. Este método não é o melhor, porque se a velocidade do retângulo for alta, você poderá ver a reposição feita por código.

Outro método é testar a colisão com um Raycast, para que você possa visualizar uma colisão antes que ela aconteça.

Dê uma olhada no msdn para obter documentação sobre a colisão de Raycast e você poderá fazer isso.

Jean
fonte