Найшвидший спосіб згрупувати одиниці, які можуть бачити один одного?


12

У 2D грі, з якою я працюю, ігровий движок може надати мені для кожної одиниці список інших одиниць, які знаходяться в її зоні перегляду.

Мені хотілося б знати, чи існує встановлений алгоритм для сортування одиниць за групами , де кожна група буде визначена всіма тими одиницями, які "пов'язані" один з одним (навіть через інші).

Приклад може допомогти зрозуміти питання краще (E = ворог, O = власна одиниця). Спочатку дані, які я отримаю від ігрового двигуна:

E1 can see E2, E3, O5
E2 can see E1
E3 can see E1
E4 can see O5
E5 can see O2
E6 can see E7, O9, O1
E7 can see E6
O1 can see E6
O2 can see O5, E5
O5 can see E1, E4, O2
O9 can see E6

Тоді я повинен обчислити групи так:

G1 = E1, E2, E3, E4, E5, O2, O5
G2 = O1, O9, E6, E7

Можна з упевненістю припустити, що для поля зору існує комутативна властивість: [якщо A бачить B, то B бачить A].

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

Заздалегідь дякую за допомогу!


1
Я думаю, що це питання є загальним для того, щоб він міг отримати кращі відповіді в стаціонарному потоці або, можливо, навіть математиці (теорія множин?). Це не конкретна розробка ігор.
Tor Valamo

1
@Tor - Мабуть, правда, але той факт, що ми знаємо, що це для гри, може дозволити людям розробляти відповіді, більш конкретні для проблеми.
Роберт Фрейзер

Я думаю, ви могли б зробити кілька розумних речей із закруткою на просторовому хешировании та картою видимості - мені просто потрібно подумати над цим.
Джонатан Дікінсон

Відповіді:


7

Якщо ваше відношення "може бачити" симетричне, так що "A може бачити B" означає "B може бачити A", то групи, які ви хочете обчислити, - це з'єднані компоненти графіка, визначені відношенням "може бачити". Як зазначали інші, існують прості алгоритми їх обчислення, такі як:

while ungrouped units remain:
    let u = arbitrary ungrouped unit
    let g = new group
    let s = temporary stack
    assign u to g
    push u onto s
    while s is not empty:
        let v = topmost unit in s
        remove v from s
        for each unit w that v can see:
            if w is ungrouped:
                assign w to g
                push w onto s
            end if
        end for
    end while
 end while

(Черга або будь-яка інша колекція, яка ефективно реалізує операції "додати новий елемент" та "видалити і повернути якийсь елемент", може бути використана замість стека sвище.)

Якщо ваше відношення "може бачити" не симетричне, вам потрібно вирішити, чи хочете, щоб ваші групи були сильно або слабо пов'язаними компонентами. Для слабко підключених компонентів алгоритм, описаний вище, буде таким, як є, за винятком того, що рядок for each unit w that v can seeслід замінити for each unit w that can see v, or that v can see. Для сильно пов'язаних компонентів , ви можете використовувати один з алгоритмів ( Kosaraju - х , Тар'я - й або Gabow - х ) , зазначені на сторінці Вікіпедії пов'язано.

Для несиметричних відношень ви також можете обчислити перехідне закриття відношення або його сильно пов'язаних компонентів. Для цього можна використовувати алгоритм Floyd – Warshall ; див. цю відповідь на SO для (трохи) додаткової інформації.


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

Половина цього легка: якщо дві одиниці в різних групах набувають між собою пряму зору, об'єднайте групи. Справа з підрозділами, що втрачають приціл один до одного, трохи складніше; одне просте, але, мабуть, не оптимальне рішення - це повторний алгоритм групування для одиниць у зачепленій групі, коли це станеться. Ви можете зробити деякі оптимізації для цього, якщо зміни видимості відбуваються по одній парі одиниць одночасно:

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

4

У вас є графік підключення. І взагалі, найкращий спосіб згрупувати підключені вузли (тобто символи) разом з алгоритмом пошуку графіків. Глибина перша, ширина перша, що залежно від того. Все, що ви робите, - це складання списку, до яких вузлів можна дістатися від усіх інших. Поки ваш графік непрямий (якщо A видно B, то B видно A), це працює добре.

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

Але взагалі вам доведеться повторно перевірити видимість кожного кадру. Шанси є, що це буде повільніше, ніж обхід графіків для пошуку груп видимості.


3
Просто додати технічний термін: те, що ви намагаєтеся знайти, - це з'єднані компоненти графіка, а стандартний алгоритм: (1) помістити всі вузли в список, (2) вибрати вузол, (3) знайти всі підключені вузли за допомогою BFS / DFS, (4) видалити всі знайдені вузли зі списку, (5) повторити, поки не залишиться більше вузлів.
Натан Рід

3

Схоже, стандартна проблема підключення графіка. Для цього може бути якийсь алгоритм, і це може виглядати наступним чином:

remaining units = all units
for each unit in remaining units:
    current group = create a new group
    add this unit to current group
    for each unit visible to this unit:
        if unit is in a group already:
            merge current group into that existing group
            set current group as that existing group
        else:
            remove that unit from remaining units
            add that unit to current group

Я думаю, що це можливо реалізувати за допомогою дерева, як ієрархічна кластеризація, але я сумніваюся, що це вийде швидше - дерева мають тенденцію бути O (log N), тоді як більшість перевірок, які я даю вище, можна реалізувати як O (1) .


Нецікавий ієрархічний підхід кластеризації приблизно такий: Для кожної одиниці створіть групу. Потім для кожної пари одиниць, які можуть бачити один одного, якщо вони в різних групах, об'єднайте групи в одну, а відкиньте іншу.
Килотан

Це те, що я назвав наївною реалізацією у своїй ОП. Приємно знати, що це може бути не так погано, як я думав тоді! :)
mac

Те, як ви робите це як дерево - це використовувати набір об'єднань із стисненням шляху . Це не дуже наївно, а насправді це оптимально.
Пітер Тейлор

2

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.