Яку поведінку або логіку рульового управління я можу використовувати, щоб мобільні телефони оточили іншого?


10

Я використовую пошук шляху в своїй грі, щоб вести мафію до іншого гравця (переслідувати їх). Це спрацьовує, щоб перевернути програвач, але я хочу, щоб вони трохи зупинилися перед пунктом призначення (тому вибір передостаннього вузла працює добре).

Однак, коли багато мобільних переслідують мобільний, вони іноді "складаються один на одного". Який найкращий спосіб уникнути цього? Я не хочу ставитися до натовпів як до непрозорих і заблокованих (тому що їх немає, ви можете пройти через них), але я хочу, щоб мафи мали певне відчуття структури.

Приклад:

Уявіть, що кожна змія орієнтувалася на мене і повинна оточувати "Сецуну". Зауважте, як обидві змії обрали мене назустріч? Це не сувора вимога; навіть трохи зсув це добре. Але вони повинні "оточити" Сецуну.

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


1
Це укладання лише питання в пункті призначення або також під час перевезення? Я здогадуюсь останнього.
SpartanDonut

Це останнє, @SpartanDonut
Vaughan

@KromStern Я додав фотографію, сподіваюся, що це допоможе.
Vaughan Hilts

Відповіді:


15

Дайте вашим агентам слабкий "електростатичний заряд", щоб вони відштовхували один одного, відповідно до закону Кулона .

Припускаючи для простоти, що натовпи повинні відштовхувати один одного з еквівалентною силою, йому повинно бути достатньо прикласти силу між кожною парою мобів з величиною some_constant / distance^2, де some_constantможна налаштувати силу відштовхування і distanceвідстань, яка їх розділяє.

Сили відштовхування потім падають із квадратом відстані.

Nature of Code має чудовий приклад (з демонстрацією наживо) тут . Це виглядає приблизно так:

комбінована послідовність та окрема поведінка

Узгодження кожного елемента один з одним - це O(n^2)операція з квадратичним часом ( ). Якщо у вас дійсно багато агентів, ви можете оптимізувати обчислення сили за допомогою наближення Барнса-Хата , яке зводить його до лінійного журналу ( O(n log n)), але вимагає квадрату .


Чудова посилання, Анко. Цінується! Я обов'язково повинен прочитати весь цей сайт.
Vaughan Hilts

Starcraft (як мінімум, 1) робить щось подібне зі своїми літаючими одиницями. Але це робиться лише тоді, коли вони перестають рухатися, тобто коли вони рухаються, вони стискаються один на одного (повністю ігнорують один одного як перешкоди), але коли вони зупиняються, вони починають поширюватися з того, що виглядає як локальний центр якоїсь регулярної площі (площа, мабуть), яка охоплює їх. Це виглядає не так добре, як приклад у відповіді, але, ймовірно, використовується менше ресурсів процесора, і, можливо, простіше також
кодувати

@ShivanDragon SC2 демонструє однакову поведінку, всі вони сходяться до місця призначення в натовпі, а потім виділяють місця для набору реалістичного та естетичного вигляду (тому їх частини не обтинаються).
Кролтан

2
Якась сила відштовхування може бути хорошою ідеєю, але деталі складні. Я експериментував з ними в просторі тематичних РТС і рекомендую не слідкувати за фізикою занадто уважно, а скоріше моделювати її, щоб вона поводилася чудово. Деякі спостереження: 1) Оскільки це не фізичне моделювання, я застосував би силу лише на невеликих відстанях. 2) Це не може запобігти перекриттю кінцевих тіл. 3) Важкий потенціал легко спричиняє числові помилки, наприклад, переломлення частинок на великих швидкостях. 4) Після того, як у вас в середині піднімається значна кількість частинок і тиск, речі, як правило, стають некрасивими.
CodesInChaos

1

Мій підхід схожий на @ Anko, але заснований на роботі Міллінгтона та Funge з Artificial Intelligence for Games .

Ось як виглядатиме поведінка розділення, але вам потрібно врахувати, що ця швидкість повинна обчислюватися зі швидкістю агента в його функції оновлення.

public Vector3 GetSeparationVel (float threshold, float decayCoefficient)
{
    threshold = threshold * threshold;
    Vector3 separationVelocity = Vector3.Zero;
    for (int i = 0; i < enemies.Length; i++) {
        if (enemies[i] == this) {
            continue;
        }
        Vector3 direction = this.position - enemies[i].position;
        float distance = direction.LengthSquared();
        float strenght = 0.0f;
        if (distance < (threshold)) {
            strenght = Math.Min(decayCoefficient / distance, this.maxAccel);
            direction.Normalize();
            separationVelocity += strenght * direction;
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.