Рулевое управление

8

Я сделал небольшой симулятор рулевого управления, используя алгоритм Рейнольдса Бойда. Теперь я хочу добавить функцию предотвращения стен. Мои стены в 3D и определены с использованием двух таких точек:

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

У моих агентов есть скорость, позиция и т. Д.

Не могли бы вы рассказать мне, как избежать моих агентов?

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

Затем я использую все силы, возвращаемые функциями boid, и применяю их к своему агенту.

Мне просто нужно знать, как это сделать со своими стенами.

Спасибо за вашу помощь.

Vodemki
источник
2
Вы смотрели на оригинальную статью Рейнольда? Если я правильно помню, у него есть информация о том, как избежать препятствий и избегать стен. Я думаю, что это документ: red3d.com/cwr/steer/gdc99
Кролт
1
Спасибо, но это объясняет, как избежать кругового препятствия, а не прямоугольного.
Водемки
2
Используйте радиальное расстояние от агента до центра круга ( минус радиус стенки круга ).
Бобобобо

Ответы:

14

Пусть каждая стена оказывает влияние на скорость.

Попробуйте что-то вроде использования обратного расстояния (или обратного квадрата расстояния) от стены, чтобы определить величину силы, которую "оказывает" каждая стена, и нормали стены, чтобы определить направление силы, которую "оказывает" стена.

введите описание изображения здесь

Так что здесь бойд взаимодействует с 4 стенами. Поскольку скалярное произведение красных векторов (boid-to-wall-center) больше 0 для 3 из 4 стенок, эти стенки не будут оказывать силы на boid.

Только стена с синим вектором (произведение отрицательных точек) будет иметь силу.

Величина силы должна быть большой, так как штанга оказывается слишком близко к стене, а направление силы должно быть в направлении черной стрелки на стене (указывающей прямо от стены).

введите описание изображения здесь

Если вы используете 1 / (t+1)для величины силы, где tрасстояние от стены, то сила будет очень сильной, когда приближается к 0, но исчезает ни к чему, когда t становится выше (обратите внимание на масштаб оси на диаграмме, это это не 0 при Т = 5, то 0,2). (Т + 1 такова, что вы не получите бесконечное усилие / деление на 0, если случится, что бид попадет в стену).

Если вы используете 1/(t^2+1), то сила у стены намного острее и падает быстрее / плавнее.

введите описание изображения здесь

Поэкспериментируйте с этим и посмотрите, что вам нравится.

bobobobo
источник
Спасибо, но как бороться с 3D стеной. Например, моя стена имеет 4 ребра, поэтому я считаю, что мне нужно максимум 2 силы (если направление агента по диагонали).
Водемки
В 2D каждые 2 точки являются «стеной». Если это квадратный столб в центре комнаты, то у вас есть 4 стены. Вы можете "отбраковать" стены с обратной обшивкой (чтобы стены с обратной обшивкой не "сосали" игрока), если вектор от boid к центру стены имеет положительное произведение точек с нормалью стены.
Бобобобо
Итак, вы думаете, это сделает работу? Расстояние Vector2D (wallList [i] -> center (), pos); double dotProduct = расстояние * wallList [i] -> normal (); if (dotProduct> 0) {force + = wallList [i] -> normal () / distance.length (); }
Водемки
Это выглядит разумно, проверьте это!
Бобобобо
Недостатком этого подхода является то, что рулевое управление моделируется как сила отталкивания, которая не зависит от движения агента. То есть он рассматривает агент как заряженную частицу в электростатическом поле. Рассмотрим случай, когда агент «летит» параллельно этой верхней (синей) стене и немного над ней (на странице). В этом случае рулевое управление или обход препятствий не требуются. Агент просто проходит мимо, и его не следует отталкивать от стены. См., Например, «сдерживание» в этом документе GDC 99 .
Крейг Рейнольдс
8

Если кому-то нужен код, вот он, не стесняйтесь распространять его. Я попытался прокомментировать это, чтобы быть более понятным. Основано на решении бобобо .

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
источник