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?

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.


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.

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.