Pull to refresh

Boids — простой алгоритм перемещения групп юнитов

Reading time 3 min
Views 31K
Во время разработки клона одной игрушки мне понадобилось перемещать группы юнитов от одной планеты к другой. Первое что пришло в голову — заспавнить юниты один за другим и двигать их по прямой. Но это выглядело не очень весело, кроме того — нужно было как-то обходить планеты. После беглого ознакомления с алгоритмами группового перемещения я решил попробовать Boids. В итоге получилось такое:



Под катом описание алгоритма с примерами кода.


Описание

Алгоритм Boids был создан Крейгом Райнольдсом (Craig Reynolds) в 1986-м году как модель перемещения стаи птиц. В его основе лежат три следующих правила:
  • Сплоченность — юниты стараются держаться как можно ближе друг к другу
  • Разделение — юниты стремятся разойтись с целью держаться друг от друга на некотором расстоянии
  • Выравнивание скоростей — юниты из одной группы стремятся двигаться с одинаковой скоростью

В качестве дополнения к ним я воспользовался ещё двумя:
  • Движение к цели — юниты стараются двигаться к заданной цели
  • Избегание препятствий — юниты стремятся в противоположную сторону от препятствий

Об имплементации

Для каждого юнита необходимо хранить хранить координаты и скорость. Так же нужно знать координаты цели и препятствий. Во время пересчёта игрового мира (пересчёт можно делать, к примеру, 20 раз в секунду) нужно определить новую координату и скорость для всех юнитов. Для этого необходимо определить новую скорость юнита и передвинуть его.

Каждое из правил, перечисленных выше, позволяют получить часть скорости. Общая скорость юнита — сумма скоростей, полученных после применения правил и предыдущей скорости самого юнита.
v1 = Rule1();
v2 = Rule2();
v3 = Rule3();
unit.v = v1 + v2 + v3 + unit.v;
unit.pos = unit.pos + unit.v;

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

Правила реализуются так:
  1. Сплоченность — необходимо найти центр масс (среднее арифметическое координат всех юнитов) и определить вектор, направленный от текущего юнита в центра масс.
  2. Разделение — нужно определить среднее направление от всех ближайших юнитов.
  3. Выравнивание скоростей — необходимо найти среднюю скорость всех юнитов.
  4. Движение к цели — вектор, направленный от юнита в сторону цели.
  5. Избегание препятствий — совпадает со вторым, за исключением того что направление нужно искать в сторону от ближайших препятствий.

На практике скорости, выданные каждым из правил необходимо уменьшать (путём деления на какой-то коэффициент) или ограничивать. Ограничения и коэффициенты подбираются экспериментальным путём для достижения наилучшего результата.

Код

А теперь немного кода. Основной код, занимающийся перемещением всех юнитов (Ships — речь идёт о космических кораблях): pastebin.com/jeHCWr8u Кроме вышеописанного тут ещё проверяется столкновение юнитов с планетами и вылет за пределы мира. Ограничение скорости — нормированный вектор (представляющий собой направление), умноженный на ограничивающий коэффициент: pastebin.com/a57hh76V

Реализация правил: pastebin.com/YDSTDh3t Особенности реализации — часть правил применяются только к юнитам из текущей группы (принадлежащих одному игроку и имеющими одну и ту-же цель). Distance — расстояние в геометрическом смысле.

Спавнинг кораблей реализован следующим образом. У каждой планеты имеется очередь кораблей, ожидающих спавнинга. Когда игрок отдаёт команду — создаётся несколько кораблей (от 1-го до ~20, в зависимости от количества энергии) и заносятся в очередь планеты: pastebin.com/FprtwTy4 А затем, каждые 50 миллисекунд спавнится по одному кораблю: pastebin.com/Tq4cvNbB

Плюсы и минусы

Алгоритм больше подходит для симуляции «живых» юнитов. Его хорошо применять в тех случаях, когда допустимо «роевое» поведение группы. В случае, если необходимо организовать более строгое движение юнитов, скорее всего придётся воспользоваться другим алгоритмом (или какой-то из модификаций). Так же мне не удалось организовать проход одной группы юнитов через другую при их перпендикулярном движении — либо одна группа начинала сталкивать другую с траектории (и в итоге обходила её сбоку) — либо юниты одной группы начинали проходить сквозь юнитов из второй (почти не огибая их). На встречных курсах ситуация лучше — иногда одна группа разделяла вторую на две и проходила по центру, а иногда проходила рядом с ней. В целом, путём многократного экспериментирования с параметрами, Boids позволят добиться хорошо выглядящих результатов, подходящих для разных ситуаций.

Ссылки

en.wikipedia.org/wiki/Boids — описание алгоритма в википедии
www.kfish.org/boids/pseudocode.html — псевдокод boids — с описанием некоторых эвристик
habrahabr.ru/post/105639 — описание boids и его различных вариаций (более теоретическое)
github.com/bakwc/ozifi/tree/master/projects/space_capture — исходники (реализация boids в server/world.cpp)
Tags:
Hubs:
+57
Comments 23
Comments Comments 23

Articles