Direção anti-parede

8

Eu estou fazendo um pequeno simulador de direção usando o algoritmo boid de Reynolds. Agora eu quero adicionar um recurso para evitar paredes. Minhas paredes são em 3D e definidas usando dois pontos assim:

   ---------. P2
   |        |
P1 .---------

Meus agentes têm velocidade, posição, etc ...

Você poderia me dizer como evitar meus agentes?

Vector2D ReynoldsSteeringModel::repulsionFromWalls()
{
    Vector2D force;
    vector<Wall *> wallsList = walls();
    Point2D pos = self()->position();
    Vector2D velocity = self()->velocity();

    for (unsigned i=0; i<wallsList.size(); i++)
    {
        //TODO
    }

    return force;
}

Então eu uso todas as forças retornadas pelas minhas funções boid e aplico ao meu agente.

Eu só preciso saber como fazer isso com minhas paredes.

Obrigado pela ajuda.

Vodemki
fonte
2
você olhou para o artigo original de Reynold? Se bem me lembro, ele tem informações sobre como evitar obstáculos e evitar paredes. Eu acho que este é o doc: red3d.com/cwr/steer/gdc99
krolth
11
Obrigado, mas explica como evitar obstáculos circulares, não retangulares.
Vodemki
2
Use a distância radial do agente até o centro do círculo ( menos o raio da parede do círculo ).
22412 bobobobo

Respostas:

14

Deixe que cada parede exerça influência na velocidade.

Tente algo como usar a distância inversa (ou distância ao quadrado inversa) da parede para determinar a magnitude da força que cada parede "exerce" e o normal da parede para determinar a direção da força que a parede "exerce".

insira a descrição da imagem aqui

Então aqui o boid interage com 4 paredes. Como o produto escalar dos vetores vermelhos (centro da boid-to-wall) é maior que 0 para 3 das 4 paredes, essas paredes não exercerão uma força sobre a boid.

Somente a parede com um vetor azul (produto de ponto negativo) terá força.

A magnitude da força deve ser grande com o boid muito próximo da parede, e a direção da força deve estar na direção da seta preta na parede (apontando diretamente para fora da parede).

insira a descrição da imagem aqui

Se você usar 1 / (t+1)a magnitude da força, onde testá a distância da parede, a força será realmente forte quando chegar perto de 0, mas desaparecerá quando nada for maior (observe a escala do eixo no diagrama, não é 0 quando t = 5, é 0,2). (O t + 1 é para que você não obtenha uma força / divisão infinita por 0 se o boid entrar na parede).

Se você usar 1/(t^2+1), a força é muito mais nítida perto da parede e cai mais rápido / mais suave.

insira a descrição da imagem aqui

Experimente e veja o que você gosta.

bobobobo
fonte
Obrigado, mas como lidar com uma parede 3D. Por exemplo, minha parede tem 4 arestas, então acredito que preciso apenas de 2 forças no máximo (se a direção do agente estiver na diagonal).
Vodemki
Em 2D, a cada 2 pontos é uma "parede". Se é um pilar quadrado no meio de uma sala, então você tem 4 paredes. Você pode "separar" as paredes externas (para que as paredes externas não "sugem" o player) se o vetor do boid ao centro da parede tiver um produto positivo com a parede normal.
bobobobo
Então, você acha que isso faria o trabalho? Distância Vector2D (wallsList [i] -> center (), pos); dotProduct duplo = distância * wallsList [i] -> normal (); if (dotProduct> 0) {force + = wallsList [i] -> normal () / distance.length (); }
Vodemki 11/12/12
Parece razoável, teste-o!
bobobobo
Uma desvantagem dessa abordagem é que a direção é modelada como uma força repulsiva que é independente do movimento do agente. Ou seja, trata o agente como uma partícula carregada em um campo eletrostático. Considere o caso em que o agente está “voando” paralelamente à parede superior (azul) e ligeiramente acima dela (na página). Nesse caso, nenhuma direção ou desvio de obstáculos é necessária. O agente está simplesmente passando e não deve ser empurrado para longe da parede. Veja, por exemplo, "confinamento" neste documento GDC 99 .
Craig Reynolds
8

Se alguém precisar do código, aqui está, sinta-se à vontade para redistribuí-lo. Eu tentei comentar para ser mais compreensível. Baseado na solução de bobobobo .

Vector2D ReynoldsSteeringModel::repulsionFromWalls(vector<Vector2D *> walls)
{
    Vector2D force; // My force will be stored here
    Point2D pos = self()->position(); // Position of the agent

    // For each wall
    for (unsigned j=0; j<walls->size(); j++)
    {
        // Get the center point of the wall
        Real coordX = (walls[j]->p1().x() + walls[j]->p1().y()) / 2.0;
        Real coordY = (walls[j]->p2().x() + walls[j]->p2().y()) / 2.0;
        Point2D center(coordX, coordY);

        // Create a new vector between my agent and the center of the current wall
        Vector2D distance(center, pos);

        // If the wall is visible, calculate the force to apply
        double dotProduct = distance * partsList[j]->normal();
        if (dotProduct < 0)
        {
            force +=  partsList[j]->normal() / (distance.length() * distance.length() + 1);
        }
    }

    // Returned the calculated force
    return force;
}
Vodemki
fonte