Пошук * навігаційної сітки


15

Отже, я робив цю гру в 2D гру Java на цій основі під назвою Greenfoot, і я працював над AI для хлопців, з якими ти збираєшся битися. Я хочу, щоб вони могли реально рухатися по всьому світу, тому я незабаром зрозумів, що серед кількох інших речей мені знадобиться якесь проходження маршруту.

Я зробив два прототипи A *. Один - на основі сітки, а потім я зробив такий, який працює з точковими точками, тому зараз мені потрібно розробити спосіб пройти з 2d "карти" перешкод / ​​будівель до графіка вузлів, з яких я можу зробити шлях. Фактичне накладання маршрутів здається прекрасним, просто мої відкриті та закриті списки можуть використовувати більш ефективну структуру даних, але я до цього довідаюся, якщо і коли потрібно.

Я маю намір використовувати навігаційну сітку з усіх причин, викладених у цій публікації на ai-blog.net . Однак проблема, з якою я зіткнулася, полягає в тому, що те, що A * вважає найкоротшим шляхом від центрів / країв полігону, не обов'язково є найкоротшим шляхом, якщо ви проїжджаєте через будь-яку частину вузла. Для кращого уявлення ви можете побачити питання, яке я задав на stackoverflow .

Я отримав хорошу відповідь щодо графіка видимості. З тих пір я придбав книгу ( Обчислювальна геометрія: Алгоритми та програми ) та прочитав далі тему, однак я все ще прихильний до навігаційної сітки (Див. " Управління складністю " з приміток Аміта про пошук шляху ). (Як бічна примітка, можливо, я міг би використати Theta * для перетворення декількох точкових точок в одну пряму, якщо перша і остання не затьмарені. Або кожен раз, коли я рухаюсь назад, перевірте, до останньої точки, щоб побачити, чи можу я перейти прямо з що до цього)

Отже, в основному те, що я хочу, - це навігаційна сітка, де після того, як я перекладу її через алгоритм воронки (наприклад, цей з Digesting Duck ), я отримаю справжній найкоротший шлях, а не отримаю той, який є найкоротшим шляхом, наступним за вузлом до вузла, але не справді найкоротший з огляду на те, що ви можете пройти кілька полігонів і пропустити вузли / краї.

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

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


Я не впевнений, але ці посилання можуть допомогти: gamedev.stackexchange.com/questions/1327/… gamedev.stackexchange.com/questions/8087/… також виникло ще одне питання щодо пошуку шляхів, яке я зараз не можу знайти. , яка отримала щедрість і мала дуже гарну відповідь.
Ali1S232

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

Насправді я просто прочитав статтю в gamedev.stackexchange.com/questions/8087/… і, здається, працює, знайшовши маршрут з A *, потім обчислює справжню вартість за допомогою зміненого алгоритму воронки, а потім знаходить інший маршрут і обчислює його справжню вартість знову і перевірити, чи вона коротша за іншу. Це повторюється, поки не дізнається, що знайдений найкоротший маршрут. Це дійсно вирішує мою проблему, проте, схоже, це буде досить повільно, оскільки ви повторюєте і випрямлення, і пошук шляху, що було б досить дорого.
сердитийпрост

Зберігання полігону: зберігайте лише видимі багатокутники - або пов'язуйте тег з кожним багатокутником (пам’ятайте, що кожен багатокутник повинен бути круглим списком вершин); аналогічно з вузлами ви можете зберігати ідентифікатор багатокутника, з якого вони походять, - але мені не потрібно говорити про це: це елементарне зберігання даних. Нарешті, чому ви дбаєте про справжній найкоротший шлях? У вашій грі собака може працювати повільно, або у вас можуть бути трохи неправильні шляхи: виберіть одну. Отримання справжнього найкоротшого шляху ПОТРІБНО вимагає повного пошуку вшир (принаймні над графіком вузла).
Джонатан Дікінсон

@JonathanDickinson Я знаю, що мені не потрібен шлях, який буде на 100% точним до останнього пікселя, і я знаю, що можу використовувати A * для отримання шляхів, які будуть не більше p допустимими. Справа проходить довгий шлях навколо перешкоди, як у моєму попередньому запитанні про переповнення стека або в gamedev.stackexchange.com/questions/8087/… просто занадто багато. Я не можу дозволити моєму AI ходити таким чином навколо перешкоди!
сердитийпрост

Відповіді:


14

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

Як ви вже зрозуміли, є два кроки для створення гарного вигляду - A-finder шляху, а потім подальша післяобробка, яка включає випрямлення контуру (усунення будь-яких поворотів, не потрібних для уникнення перешкод) і, можливо, також додавання кривих у точках повороту.

Шлях пошуку

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

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

Наступним найпростішим рішенням є виконання A * від краю до краю через сітку. Ви можете думати над цим простіше, якщо ви уявите, що замість одного вузла на багатокутник у вас є один за край на багатокутник. Таким чином, ваш шлях йде від початкової точки до просто всередині найближчого краю, перетинає лише до краю сусіднього багатокутника, а потім просто до наступного краю в тому ж полігоні тощо. Це створює найкоротший шлях частіше, а також має перевагу проходу, якщо ви не хочете виконувати крок випрямлення шляху.

Випрямлення контуру

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

Алгоритм випрямлення траси Детура не є досить складним O (n), оскільки коли він визначає, що йому потрібно вставити поворот, він вставляє його в точку, де востаннє затягує воронку вліво (при повороті вліво і навпаки) і потім знову починає простежувати вузли з цієї точки.

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

Потім ви можете виконувати цей тест на випромінювання, коли алгоритм воронки визначає, що потрібно вставити поворот, щоб побачити, чи справді це так, але я думаю, вам доведеться продовжувати виконувати цей тест на кожному вузлі, поки ви не вставите поворот (у який момент можна повернути до простого алгоритму воронки). Це буде дорого коштувати, зробивши шлях випрямленням приблизно O (n ^ 2).

Представляючи навмеш

Ви можете представити свою сітку як масив багатокутних класів. Клас багатокутника може бути таким же простим, як масив вершин і масив посилань на сусідній багатокутник для кожного краю, якщо такий є. Звичайно, ви, напевно, можете придумати способи зберігати їх більш компактно. Оскільки вершина зазвичай поділяється кількома багатокутниками, нормально мати один великий масив вершин, а потім кожен індекс багатокутника зберігати в цьому масиві. Залежно від характеристик вашого навмеша, у вас може бути середня кількість з'єднувальних ребер, що становить лише 50% або менше від кількості ребер. У цьому випадку ви можете захотіти зберегти посилання на інший многокутник та індекс краю, а не зберігати посилання для кожного краю. Також я рекомендую вам зберігати індекс многокутника в масиві багатокутника navmesh, а не використовувати посилання на клас.


Я щойно прочитав це, але розумію, що ви ніколи не повинні використовувати квадрат відстані (або не квадратний його корінь) для A *: теорія.stanford.edu
~amitp/

Мене не дуже хвилює питання про те, як насправді піти атм випрямлення траси, те, що мене турбує, - це те, що ви говорите: "Ви повинні спостерігати, що це лише випрямить шлях у межах полігонів, знайдених під час пошуку A *. Таким чином, якщо це не знайде найкруткіший шлях навколо перешкоди, ви також не отримаєте тісний шлях після запуску цього алгоритму ".
сердитийпрост

Я хочу мати навігаційну сітку, де A * завжди знайде виправлений шлях найкоротший, незалежно від вартості проїзду через вершини / середини. Я розумію, що це можна зробити за допомогою графіка видимості, але я хочу використовувати navmesh, оскільки він має багато інших переваг і тому, що складність графіка видимості може зрости дуже швидко: теорія.stanford.edu/~amitp/GameProgramming/…
сердитийпрост

@theguywholikeslinux можна використовувати евклідову відстань sqrt(x*x + y*y)- але не дешевший за вузол x*x + y*y.
Джонатан Дікінсон

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