Como encontro a interseção de duas linhas


7

Eu tenho uma caixa delimitadora no meu personagem, sua posição no quadro anterior e o quadro atual. A caixa delimitadora é alinhada ao eixo.

Meu personagem está correndo dentro de uma caverna, tenho uma lista de pontos (linhas) que representam a parede da caverna (não alinhada ao eixo)

Eu tenho um algoritmo de granulação grossa que me diz quando alguma parte do meu personagem provavelmente colidiu com alguma parte da parede da caverna.

Eu não tenho um algoritmo de granulação fina para me dizer especificamente qual linha da parede foi colidida e em que ponto.

Meu pensamento atual era que eu poderia criar uma linha para cada canto da caixa delimitadora, da posição no quadro anterior até a posição no quadro atual e, em seguida, testar cada uma dessas linhas para interseções com qualquer uma das linhas da caverna parede.

Meu google fu, no entanto, não me mostrou uma fórmula fácil para calcular cruzamentos. Eu escolhi uma maneira ruim de fazer isso ou sou apenas ruim na pesquisa?

Meu jogo é escrito em scala, no entanto, eu posso ler / traduzir praticamente qualquer linguagem de estilo c e muitas linguagens de script, o que você quiser responder

Respostas:


-3

pesquisando no Google "o segmento de linha de teste de interseção" produziu:

http://paulbourke.net/geometry/lineline2d/


2
A solução é maior do que apenas o ponto de interseção entre duas linhas. Trav tem um número de linhas que descrevem o terreno e qualquer parte do personagem pode estar se cruzando com qualquer parte de qualquer linha do terreno.
Doppelgreener

Isso é apenas uma repetição do algoritmo. A fórmula para testar a presença de um cruzamento, seja nos segmentos que eu estou olhando, e em seguida, obter a localização específica é exatamente o que eu estou atrás
O Trav

11
A razão pela qual eu respondi à resposta é porque sim, é uma repetição do algoritmo e você pode forçá-lo com força bruta. Eu espero que haja mais coisas hoje em dia. Não acho que apenas apontar a fórmula matemática para a interseção de linhas faça justiça ao problema. E quando o seu nível fica decentemente grande e você está perdendo ciclos verificando se há interseção contra uma parede totalmente não relacionada?
Doppelgreener

Jonathan: Bem, a partir da pergunta: "Eu tenho um algoritmo de granulação grossa que me diz quando alguma parte do meu personagem provavelmente colidiu com alguma parte da parede da caverna". Embora nós não sabemos se esse algoritmo grosso detalhe é bom ou não ...
Olhovsky

7

Você pode fazer isso com diferentes abordagens;

  • segmento vs segmento usando linhas paramétricas mais algumas verificações (porque as linhas não são segmentos).

  • segmento vs caixa

  • segmento vs círculo (este seria o meu favorito)

. Mas, como você solicita um teste de interseção de segmento versus segmento, aqui está um pseudo exemplo de C ++ extraído do livro muito interessante "Detecção de colisão em tempo real":

float Signed2DTriArea(Point a, Point b, Point c)
{
    return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
}

int Test2DSegmentSegment(Point a, Point b, Point c, Point d, float &t, Point &p)
{
    // signs of areas correspond to which side of ab points c and d are
    float a1 = Signed2DTriArea(a,b,d); // Compute winding of abd (+ or -)
    float a2 = Signed2DTriArea(a,b,c); // To intersect, must have sign opposite of a1

    // If c and d are on different sides of ab, areas have different signs
    if( a1 * a2 < 0.0f ) // require unsigned x & y values.
    {
        float a3 = Signed2DTriArea(c,d,a); // Compute winding of cda (+ or -)
        float a4 = a3 + a2 - a1; // Since area is constant a1 - a2 = a3 - a4, or a4 = a3 + a2 - a1

        // Points a and b on different sides of cd if areas have different signs
        if( a3 * a4 < 0.0f )
        {
            // Segments intersect. Find intersection point along L(t) = a + t * (b - a).
            t = a3 / (a3 - a4);
            p = a + t * (b - a); // the point of intersection
            return 1;
        }
    }

    // Segments not intersecting or collinear
    return 0;
}

O contrato de licença de software do livro solicita a inclusão do seguinte crédito para usar os exemplos de código:

exemplo de código "da Real-Time Collision Detection, de Christer Ericson, publicado pela Morgan Kaufmaan Publishers, © 2005 Elvesier Inc"


4

Embora alguém já tenha fornecido uma resposta considerada satisfatória, não tenho certeza de que o método que você descreveu produzirá um tempo de impacto preciso (TOI). Minha primeira inclinação é a de encontrar uma resposta exata para a pergunta: "até onde o jogador pode se mover antes de colidir com uma parte da caverna, se ocorrer alguma colisão?" requer o recurso a técnicas contínuas de detecção de colisão (CCD).

Especificamente, existe uma técnica pela qual você pode "encolher" efetivamente seu AABB em um único ponto e, ao mesmo tempo, "aumentar" os segmentos de linha da caverna na mesma quantidade usando a adição de Minkowski. Então, o problema pode ser visto como lançar um raio contra um objeto convexo ou conjunto de objetos convexos (uma vez que um ponto que se move no tempo com velocidade constante se torna um raio). A primeira distância ao longo do raio que cruza com a caverna "inchada" representará o primeiro tempo de impacto (TOI).

A literatura mais comum sobre como realizar isso lida com três dimensões, mas ainda se aplica a duas dimensões e deve ser transferida facilmente. No momento, não tenho tempo para detalhar todos os detalhes ou fornecer o código psuedo, mas talvez alguém possa verificar e expandir o que estou me referindo. Por enquanto, aqui estão alguns documentos que explicam o processo e alguns termos que você pode estar interessado em pesquisar no Google.


0

Em uma tentativa de ajudar outras pessoas que encontrarem isso em suas viagens, aqui está um teste de interseção de linha 2D usando os métodos encontrados em https://stackoverflow.com/a/1968345/431528 .

inline bool lines_intersect_2d(Vector2 const& p0, Vector2 const& p1, Vector2 const& p2, Vector2 const& p3, Vector2* i const = 0) {
    Vector2 const s1 = p1 - p0;
    Vector2 const s2 = p3 - p2;

    Vector2 const u = p0 - p2;

    float const ip = 1.f / (-s2.x * s1.y + s1.x * s2.y);

    float const s = (-s1.y * u.x + s1.x * u.y) * ip;
    float const t = ( s2.x * u.y - s2.y * u.x) * ip;

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
        if (i) *i = p0 + (s1 * t);
        return true;
    }

    return false;
}
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.