Відповіді:
Як правило, ви хочете використовувати A *, якщо немає чогось важливо іншого.
Мені потрібно було вирішити подібну проблему: пошук маршрутів на великій лабіринтній сітці з постійно мінливими "витратами" та бар'єрами.
Річ у тім, що в грі в оборону башта кількість утворень, яким потрібно вирішити шлях, зазвичай набагато більша, ніж кількість вузлів у графі. A * - це не найбільш підходящий алгоритм для вирішення цього питання, тому що вам потрібно буде вирішувати його заново кожного разу, коли щось змінюється. Що ж, це доречно, якщо вам потрібно знайти лише один шлях, але в моєму випадку мені потрібно було вміти обробляти об'єкти, які можуть з’являтися в різних місцях і до кожного має свій шлях.
Алгоритм Floyd-Warshall набагато доречніший, хоча для мого випадку я написав спеціальний алгоритм, що кожного разу, коли вузол змінюється, він перераховує вартість цього вузла від усіх його сусідів, а потім, якщо сусіди були змінені, його викликають рекурсивно на них.
Тож на початку гри я просто запускаю цей алгоритм на всі мої «цільові» вузли. Потім, кожного разу, коли один вузол змінюється (наприклад, стає непрохідним), я просто запускаю його на цей вузол, і зміна розповсюджується на всі вузли, на які буде впливати, а потім зупиняється. Тому немає необхідності в глобальному перерахунку, і алгоритм повністю незалежний від кількості сутностей, яким буде потрібно маршрутизація.
Мій алгоритм був в основному чимось на кшталт (псевдо-код):
update_node method in Node class:
$old <- $my_score
find $neighbor node among all neighbors such that
$neighbor.score + distance_to($neighbor) is minimal
$my_score <- $neighbor.score + distance_to($neighbor)
$next_node <- $neighbor
if ($my_score != $old)
for each $neighbor
$neighbor.update_node()
З початковою оцінкою залежно від того, чи є вузол цільовим чи якимсь бар'єром.
Алгоритм маршруту, який я використовував у моєму TD, був назад від звичайного A * шляху через кількість сутностей, які я мав у грі. Замість того, щоб направлятись від мети до поганих хлопців, я прямував від цілі до кожного порожнього квадрата на дошці.
Це не займе багато часу, ви просто продовжуєте ітерацію дошки, поки не знайдете свої "витрати", і це забезпечує хороший зворотній зв'язок для заблокованих маршрутів (якщо ви це робите). Використання алгоритму Floyd є швидким і кеш-пам'ятником порівняно з A *, оскільки він не здійснює пошук даних, залежний від даних, він просто завантажується і працює над даними в потоках.
Почніть із встановленої дошки нескінченної вартості, а потім встановіть квадрат мети, який дорівнюватиме нулю, а потім повторіть дошку, перевіряючи, чи коштує сусідня комірка менше поточної вартості плюс вартість поїздки. Вартість поїздки - це те, де ви поклали свої евристичні дані (у моєму випадку вартість проїзду по діагоналі була нескінченною, але вартість проїзду через вежу була високою, тому їм дозволяли їсти через вежі, але ні, якщо вони не мали вибір)
Отримавши сітку ваших витрат, ви можете швидко створити з неї сітку "потоку", випробувавши найкрутіший градієнт витрат на комірки. Це дуже добре працює для величезної кількості поганих хлопців, тому що ніхто з них ніколи не повинен знайти шлях, вони просто слідують за віртуальними покажчиками.
Ще одна перевага полягає в тому, що таким чином вам доведеться виконувати це завдання лише кожного разу, коли ви налаштовуєте перешкоди (або в моїй грі, коли повзучість їсть через одну з ваших веж). Не кожен раз, коли повзання / натовп виходить на поле (що з тисячами мобів і десятків в секунду було б досить головним болем).
Шлях пройде швидко, і на щось розмір звичайної гри в оборону башти ви не матимете проблем із виконанням повного проходу A * або Dijkstra, коли щось зміниться. Ми добре розмовляємо під мілісекундою для повного оновлення. Будь-який вид адаптивного проходження шляху закінчується жахливо складним. Просто робіть це простим способом, якщо тільки ви не зробите найбільшу в світі сітку оборони вежі.
Як працює A * просування маршрутів? може бути гарним місцем для початку :-)
Це може бути зайвим для вашого рішення, але подумайте про направлення назад, а не вперед.
У грі на TD вороги, як правило, намагаються дістатись певної мети. Шлях назад від цієї мети до першого ворога, а потім кешувати цей шлях. Під час генерації шляху для наступних ворогів використовуйте перший шлях як вихідну точку тощо. Якщо у вас є кілька точок залучення противника або кілька цілей, у вас є діапазон попередньо кешованих шляхів, з яких слід починати.
Налаштування маршрутизації шляху, ймовірно, було б найкращим для td-гри, оскільки, як правило, на основі рівня ai йде прямий шлях. В основному ви встановлюєте свої вузли чи точкові точки, після чого маєте "ай" точку до шляхової точки та йдете до неї, як тільки вона наблизиться до такої, щоб вона перейшла до наступної точки, зверніться до неї та рухайтесь до неї.
Оскільки хтось запитав, ви звертаєтесь до середовищ, що змінюються в динамічному режимі, повторно обчислюючи шлях щоразу, коли гравець розміщує або знімає вежу, і ви просто зберігаєте цей шлях у пам'яті середнього часу. Навколишнє середовище не змінюється на кожному кадрі.
Зауважте, що деякі ігри TD мають заданий шлях і не дозволяють розміщувати вежі на ньому, тому вони вирішують простеження маршруту найпростішим способом: шляхом жорсткого кодування шляху і не дозволяють вам блокувати його :)
Просте рішення - обдурити.
Заздалегідь спроектуйте карту, щоб переконатися у відсутності тупиків. Потім у кожному перехресті додайте тригер, який змушує персонажа вибирати маршрут (приклад: завжди поверніть ліворуч, завжди поверніть праворуч або випадково).