История о выборе пути
Всем привет! Несколько недель назад взялся за создание небольшой игры для стима и мобилок и сегодня хочу рассказать о первых результатах и проблемах, с которыми столкнулся в первую неделю разработки (кроме создания базовой архитектуры игры пришлось повозиться с вариантами поиска путей для отрядов).
Пару слов о самой игре. Небольшая RTS, где игроку предстоит захватывать здания противника своими отрядами, которые восполняются со временем в башнях игрока. Во время игры нужно защищать свои домики, пополнять ресурсы стреляющих башен и использовать различную магию стихий.
Недавно получил от художника и добавил в игру обновленный арт для построек и карты, так что одна из целей публикации данного поста - узнать мнение читателей на счет графики и выбранного сеттинга для данной механики.
Теперь собственно к проблеме поиска маршрутов между башнями. Первая мысль, которая приходит когда необходимо сделать передвижение отряда из точки А в точку Б без необходимости динамически менять маршрут - это заранее расставить точки на карте и передвигать по ним отряд с необходимой скоростью движения. Второй вариант был использовать одну из бесплатных библиотек динамического поиска пути A* Pathfinding Project.
После недолгого раздумья был выбран второй вариант с динамической генерацией путей. Ну в самом деле, не расставлять же программисту точки для полусотни уникальных путей для каждого уровня!
У A* Pathfinding Project есть поддержка Unity3D, так что добавить построение маршрутов в игру заняло не более пары часов. На сцене можно настраивать размер ячеек в сетке проходимости, для моей игры требовалась как минимум 70х50 сетка, средний размер пути был 40-60 точек, а результат был мягко говоря не впечатляющим:
Почитав темы с поиском пути в играх пришел к выводу, что нужно использовать сглаживание поворотов, к счастью в этой библиотеке сделать это просто: нужно добавить компонент SimpleSmoothModifier на объект с Seeker (у которого вызывается метод поиска пути). Результаты работы сглаживания меня вполне устраивали.
Без сглаживания и после использования 3 итераций:
Появилась новая проблема - даже после увеличения ячеек сетки проходимости, средняя длина сглаженного пути составляла полсотни точек. Поиск и сглаживание всех маршрутов на мобильных устройствах стал занимать безумное количество времени при загрузке уровня (в среднем +5с на планшете Nexus 7) и забивать всю оперативную память на слабом телефоне.
Вообще данная проблема решается просто: необходимо было всего лишь просчитать пути и их длину в редакторе и сохранить в префаб. Наверняка создатели библиотеки предусмотрели такую возможность...
Беглый просмотр кода в AstarPath показал, что методы поиска пути могут работать и в editor режиме, необходимо только в нескольких местах убрать строку
if (!Application.isPlaying) return;
которая прерывает выполнение метода если игра не запущена.
Чтоб использовать сглаживание пути, необходимо так же добавить аттрибут [ExecuteInEditMode] к классам Seeker и SimpleSmoothModifier, нам нужно чтоб в этих классах при запуске сцены сработал метод Awake в режиме editor и класс получил все необходимые ссылки на компоненты для работы с модификацией пути. Осталась только одна проблема - сам поиск пути происходит в методе Update, который в редакторе срабатывает при изменении свойств объектов. Можно вызывать этот метод вручную до тех пор, пока все пути не будут просчитаны, или просто потеребить какой-нибудь из объектов на сцене для срабатывания достаточного количества методов Update.
Когда с построением маршрутов проблемы были решены, для удобства создания уровней осталось написать простенький редактор с методами, которые работают в editor режиме.
1. При нажатии на первую кнопку на сцене создается новый объект, содержащий настройки для создаваемой башни. Во-первых это позволяет визуально отображать всю информацию в режиме редактора, во-вторых при изменении уровня, элемента или типа башни - скрипт автоматически пересоздает отображаемый скин. Это очень экономит время при создании схем уровней.
Слева на картинке компонент с настройками параметров башни из п.1, справа - интерфейс для ручного изменения пути из п.4
2. Когда все башни расставлены, время вызвать второй метод редактора. Он создает объекты Path из каждой башни к каждой другой башне, в которых хранится информация о координатах всех точек пути и длина этого пути. На самом деле создается только половина путей (нет смысла отдельно просчитывать путь A -> B и B->A.) На этом этапе каждый путь представляет из себя отрезок из точки А в точку B.
3. При нажатии на третью кнопку метод пробегается по всем созданным объектам Path и вызывает поиск пути между заданными точками. После этого необходимо вызвать пару десятков срабатываний метода Update у класса AstarPath до тех пор, пока все пути не будут просчитаны.
4. Если необходимо внести коррективы в какой-нибудь из путей (может получится так, что после сглаживания маршрута он начал пересекать непроходимый объект) можно выбрать этот путь и вручную перетащить часть точек.
Все что осталось сделать - это сохранить префаб с расставленными башнями, рассчитанными путями и настройками AI противника в библиотеку. Позже он будет создан и инициализирован при загрузке уровня во время игры. На этапе оптимизации игры можно будет сделать сохранение всех данных в xml файл, что позволит вносить изменения в уровень на стороне сервера и передавать его при загрузке игры.
На этом создание инструмента для построения путей между башнями было закончено. Буду рад увидеть в комментариях ваше мнение по поводу выбранного стиля графики и критику игры.
А чем тебе встроенный в юнити navmesh не угодил?
@unkxander, графическая часть довольно приятная. Играли в игру "Mushroom Wars"? Геймплейные гифки еще не делали?
Дайте, пожалуйста, ссылку на гитхаб проекта. Очень интересно посмотреть внутренности игры.