Eu implementei um lançamento de varredura 2D AABBvsAABB no meu jogo, no entanto, estou tendo dificuldade em calcular o acerto normal do elenco de varredura.
Eu tenho a direção de varredura, as posições AAB B e xy min-maxs, primeiro e último tempos de batida para trabalhar, mas não a (s) aresta (s) em colisão ou a direção normal. Simplesmente não consigo conceber uma solução eficiente para esse problema específico. Alguma ideia? :)
*editar
É isso que eu tenho até agora - apenas uma implementação geral da varredura AABB de Gomez e Christer Ericson . Não há acerto normal, portanto, embora o cálculo normal seja um mistério para mim, não consigo produzir nenhuma resposta de colisão para o meu controlador de personagem.
bool SweepVelAABBvsAABB(AABB a, AABB b, Vector2 v, out Vector2 outVel, out Vector2 norm )
{
outVel = v; //Initialise out velocity
norm = Vector2.zero;
if( AABBvsAABB(a,b) ) return true; //return early if a,b overlap
v = -v;
float hitTime = 0.0f;
float outTime = 1.0f;
if(v.x < 0.0f) //sweep is going right
{
if(b.max.x < a.min.x) return false;
if(a.max.x < b.min.x) hitTime = Mathf.Max( (a.max.x - b.min.x) / v.x, hitTime );
if(b.max.x > a.min.x) outTime = Mathf.Min( (a.min.x - b.max.x) / v.x, outTime );
}
else if(v.x > 0.0f) //sweep is going left
{
if(b.min.x > a.max.x) return false;
if(b.max.x < a.min.x) hitTime = Mathf.Max( (a.min.x - b.max.x) / v.x, hitTime );
if(a.max.x > b.min.x) outTime = Mathf.Min( (a.max.x - b.min.x) / v.x, outTime );
}
if(hitTime > outTime) return false;
//=================================
if(v.y < 0.0f) //sweep is going up
{
if(b.max.y < a.min.y) return false;
if(a.max.y < b.min.y) hitTime = Mathf.Max( (a.max.y - b.min.y) / v.y, hitTime );
if(b.max.y > a.min.y) outTime = Mathf.Min( (a.min.y - b.max.y) / v.y, outTime );
}
else if(v.y > 0.0f) //sweep is going down
{
if(b.min.y > a.max.y) return false;
if(b.max.y < a.min.y) hitTime = Mathf.Max( (a.min.y - b.max.y) / v.y, hitTime );
if(a.max.y > b.min.y) outTime = Mathf.Min( (a.max.y - b.min.y) / v.y, outTime );
}
if(hitTime > outTime) return false;
outVel = -v * hitTime;
return true;
}
collision-detection
normals
Larolaro
fonte
fonte
Respostas:
Eu consegui encontrar uma solução simples e eficiente observando os eixos de separação.
fonte
Observe como o acerto normal do A é
sum(Normals of Vectors of Edges on B involved in collision)
. Em ordem de palavras:Lembre-se de que uma "aresta" pode ser apenas um vértice ( estamos colidindo com o canto em outra caixa).
Você também notará que isso se aplica ao acerto normal de B.
fonte
Se bem entendi, seu algoritmo até agora encontra a posição ao longo do movimento de A na qual A e B estão apenas tocando.
Com essa posição, execute um teste de interseção unidimensional entre A e B nos três eixos. Um (ou mais em casos de canto) desses eixos não terá sobreposição; o acerto normal deve ser paralelo a esse eixo e na direção de B a A.
Se mais de um eixo não tiver sobreposição, você acertará uma aresta ou um canto perfeitamente; você pode escolher arbitrariamente uma opção ou somar os resultados para um canto "arredondado".
fonte