Sterzo per evitare le pareti


8

Sto realizzando un piccolo simulatore di sterzo usando l'algoritmo boid di Reynolds. Ora voglio aggiungere una funzione di evitamento del muro. Le mie pareti sono in 3D e definite usando due punti del genere:

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

I miei agenti hanno una velocità, una posizione, ecc ...

Potresti dirmi come evitare i miei agenti?

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;
}

Quindi uso tutte le forze restituite dalle mie funzioni boid e le applico al mio agente.

Devo solo sapere come farlo con i miei muri.

Grazie per l'aiuto.


2
hai guardato l'originale Reynold's paper? Se ricordo bene, contiene informazioni su come evitare gli ostacoli e evitare i muri. Penso che questo sia il documento: red3d.com/cwr/steer/gdc99
krolth l'

1
Grazie ma spiega come evitare un ostacolo circolare, non rettangolare.
Vodemki,

2
Usa la distanza radiale dall'agente al centro del cerchio ( meno il raggio della parete del cerchio ).
Bobobobo,

Risposte:


14

Lascia che ogni muro eserciti un'influenza sulla velocità.

Prova qualcosa come usare la distanza inversa (o la distanza quadrata inversa) dal muro per determinare l'entità della forza che "esercita" ogni muro e la normale del muro per determinare la direzione della forza che "esercita" il muro.

inserisci qui la descrizione dell'immagine

Quindi qui il boid interagisce con 4 muri. Poiché il prodotto punto dei vettori rossi (centro-parete-boid) è maggiore di 0 per 3 delle 4 pareti, tali pareti non eserciteranno una forza sulla boid.

Solo il muro con un vettore blu (prodotto con punto negativo) avrà una forza.

L'entità della forza dovrebbe essere grande con il boid che si avvicina troppo al muro e la direzione della forza dovrebbe essere nella direzione della freccia nera sul muro (che punta direttamente lontano dal muro).

inserisci qui la descrizione dell'immagine

Se usi 1 / (t+1)per la grandezza della forza, dov'è tla distanza dal muro, allora la forza sarà davvero forte quando si avvicina a 0, ma svanisce nel nulla quando t diventa più alta (nota la scala dell'asse nel diagramma, non è 0 quando t = 5, è 0,2). (Il t + 1 è in modo da non ottenere una forza / divisione infinita per 0 se il boid entra nel muro).

Se lo usi 1/(t^2+1), la forza è molto più acuta vicino al muro e cade più velocemente / più uniforme.

inserisci qui la descrizione dell'immagine

Sperimentalo e vedi cosa ti piace.


Grazie ma come gestire un muro 3D. Ad esempio, il mio muro ha 4 spigoli, quindi credo di aver bisogno di un massimo di 2 forze (se la direzione dell'agente è in diagonale).
Vodemki,

In 2D, ogni 2 punti è un "muro". Se è un pilastro quadrato nel mezzo di una stanza, allora hai 4 pareti lì. Puoi "abbattere" i muri di facciate (in modo tale che le pareti di facciate non "succhino" il giocatore) se il vettore dal boid al centro del muro ha un punto positivo con il muro normale.
Bobobobo,

Quindi, pensi che questo farebbe il lavoro? Distanza Vector2D (wallList [i] -> center (), pos); double dotProduct = distance * wallsList [i] -> normal (); if (dotProduct> 0) {force + = wallsList [i] -> normal () / distance.length (); }
Vodemki l'

Sembra ragionevole, provalo!
Bobobobo,

Un difetto di questo approccio è che lo sterzo è modellato come una forza repulsiva che è indipendente dal movimento dell'agente. Cioè tratta l'agente come una particella carica in un campo elettrostatico. Considera il caso in cui l'agente sta “volando” parallelamente a quel muro superiore (blu) e leggermente al di sopra di esso (sulla pagina). In questo caso, non è necessario evitare sterzate o ostacoli. L'agente sta semplicemente passando e non deve essere allontanato dal muro. Vedere ad esempio "contenimento" in questo documento GDC 99 .
Craig Reynolds,

8

Se qualcuno ha bisogno del codice, eccolo qui, sentiti libero di ridistribuirlo. Ho provato a commentarlo per essere più comprensibile. Basato sulla soluzione di 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.