Pull to refresh

Использование AI и утилит при разработке игр жанра Tower Defense

Reading time 6 min
Views 35K
Эта статья продолжает тему применения математического моделирования при разработки игр в жанре ТD. В прошлых статьях рассматривались базовые параметры основных объектов игры – крипов и башен, и их зависимость от времени раунда и размера карты, а также принципы построения внутриигровой экономики, которая не привносила бы дисбаланс на тех или иных этапах игры.

Дальнейшее развитие этой темы напрашивалось само собой: если известны основные алгоритмы, которые позволяют задавать граничные рамки игровых параметров, то эти же алгоритмы можно применять для создания AI, который позволил бы хотя бы частично заменить игрока и проверить геймплей «вживую».



Тема создания ботов-имитаций игрока для однопользовательских игр неоднократно уже всплывала на Хабре, но, как правило, они создавались либо для «спортивного интереса», либо с целью «накручивания» параметров в тех играх, где требуются монотонные действия. Однако, AI может принести пользу и в процессе разработки игры, о чем и будет первая часть данной статьи.

Для начала определимся, для чего может быть необходим AI в игре жанра Tower Defense (TD).

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

Во вторую очередь, в процессе создания бота в игру (ее отладочный вариант) была введена очень полезная функция – максимально быстрое «ускорение» прогона волны крипов, без отрисовки графики, только с обсчитыванием игровой механики. Это позволило быстро проверять работу бота, а также отлаживать баланс отдельных волн для каждой из конфигурации поля (и для различных методов расстановки башен на поле). Этот способ был необходим для проверки «на практике» применимости башен различных видов в разных ситуациях. Он позволяет за короткое время «проиграть» множество разных карт, что дает возможность собрать статистику, которая покажет, насколько математически выверенные данные совпадают с реальным положением вещей.

Если же говорить про принцип работы бота, то он имел следующий алгоритм (пункты также показывают эволюцию создания бота, его разные итерации):

1. Бот запущен постоянно и может совершить действие в любой момент – как в ожидании волны врагов, так и когда враги движутся по полю.
2. Каждый раз вычисляются пути всех волн крипов. Заметим, что в одной волне может быть несколько отрядов врагов, выходящих из разных точек.
3. Каждой ячейке поля присваивается свой «вес» в зависимости от того, сколько отрядов крипов проходит через нее. Подразумевается, что бот считает на 1 волну вперед, и знает, из каких точек пойдут крипы.
4. Также бота можно сделать более «умным», добавив знания о том, сколько и каких крипов пойдет из какой точки, с каким интервалом и т.д., то есть данные о «мощности» каждой из следующих волн/подволн.
5. «Вес» каждой из последующих волн рассчитывался исходя из того, как скоро она начнется. То есть бот вполне мог смотреть как грубо на «1 шаг вперед», так и сразу действовать «стратегически». Суммы значений для каждой ячейки для каждой из волн складывались, поэтому в итоге получалось, что каждая ячейка поля имеет одно значение – ее «вес». Разумеется, эта матрица коэффициентов изменяется в зависимости от числа оставшихся волн: уже прошедшие волны (пути их крипов) перестают учитываться в «карте весов».
6. В зависимости от того, какая ячейка имеет наибольший «вес», в эту точку ставится башня.
7. В первой итерации логика бота по профилю экономики была простейшей: как только денег хватает на башню – она покупается. Сначала использовалась только 1 башня, так как основной задачей была проверка геометрии уровня при застройке.
8. Так как установка башни в некоторые тайлы может изменить траекторию крипов, то во второй итерации был добавлен просчет поля и поведения противников на 1 ход вперед. Таким образом, для каждого из мест проверялось, что будет, если в эту точку поставить башню, изменится ли траектория движения врагов, и если да, то сколько урона нанесут им все ранее установленные башни (а не только башня, поставленная последней). Без этой возможности неоднократно бывало, что установка башни в, казалось бы, идеальное место делает остальные башни бесполезными, так как крипы начинают двигаться в обход остальной артиллерии.
9. Дальнейшее развитие бота – использование апгрейда башни. Опять таки, смотрится на 1 ход вперед, что будет выгоднее — проапгрейдить одну из башен (сначала выбиралась та башня, которая наносит больше всего урона, во второй итерации стали перебираться все башни, так как с апгрейдом увеличивался радиус башни, а значит наносимый ей урон мог измениться нелинейно), либо же поставить еще одну. Разумеется, разница наносимого урона нормировалась на цену совершения действия.
10. Далее требовалось научить бота продавать неиспользуемые башни. Это применялось в том случае, если бот «знал», что башня в месте Х на следующей волне не будет задействована. Вычислялось это аналогично принципу выбора места постройки башни, только с обратным знаком. Важно учитывать, что продажа башни возвращала только 50% ее стоимости. Поэтому башню стоит продавать, если на карте существует место, в котором установленная башня нанесет в 2 раза больше урона, чем башня в текущем месте (чтобы скомпенсировать потери при продаже).



Однако, дальнейшее развитие бота (чтобы он мог использовать другие башни, бонусы, грамотно противодействовать противникам с уникальными способностями) было признано нецелесообразным, но некоторые части этой утилиты нашли свое применение в совсем другой сфере: записи и просмотре реплеев игры.

Более того, в результате сравнения логики бота и человека на одних и тех же картах выяснилось, что бот хорошо показывает себя там, где дело касается геометрии, но действия, связанные с апгрейдом и продажей башен как правило лучше выполняет человек. Исходя из этого, были выведены следующие пункты, в которых AI показывал себя весьма неплохо:

1. Проверить, насколько легко уровень проходим исключительно базовыми башнями.
2. Проверить корректность геометрии, нет ли дисбаланса по застройке на одной из волн – по сути, проверялось, насколько много на уровне удобных точек для расстановки башен, остается ли выбор мест постройки башен у игрока хотя бы к середине уровня.
3. Проверить, проходим ли уровень вообще на первых волнах, благодаря боту можно было рассчитать адекватный баланс стартовых средств.

По сути, AI выполнил свое предназначение: помог отфильтровать неудачные карты, тем самым дав понять геймдизайнеру, какие типы геометрии уровней могут быть приемлимы с данным балансом башен и противников.

Однако, использование модуля AI было актуально и в дальнейшем, а именно: для той части кода, которая позволяла бы имитировать одиночные действия игрока – постройку башен, апгрейд, продажу, ускорение игрового времени и т.д.

Все это пригодилось для записи (и дальнейшего просмотра) реплеев от других тестеров, когда сам вектор дизайна был выбран и требовался тюнинг сложности и интересности уровней, проводимый на живых игроках. Фактически, просто изменился источник, который выдает решения – раньше этим занимался AI, теперь же вся последовательность действия считывалась из файла логов.

Запись и просмотр логов

В каждой игровой сессии записывались следующие действия:

1. Начало/конец игровой сессии,
2. Включение/выключение паузы,
3. Изменение скорости игры,
4. Досрочный вызов волны,
5. Установка башни Х в координаты АБ,
6. Апгрейд башни в месте Х,
7. Продажа башни в месте Х,
8. Для контроля – потеря кубком жизни,
9. Для контроля – выигрыш/проигрыш уровня,
10. Для контроля – факт убийства последнего крипа в волне (пишутся координаты крипа).

Пример лога

level3.lvl start; 03/22/2012 19:39:12;
level3.lvl; 6.41; build; active_tower; 5,1; 250;
level3.lvl; 10.25; build; active_tower; 9,1; 190;
level3.lvl; 12.16; upgrade; 5,1; 130;
level3.lvl; 13.86; upgrade; 9,1; 80;
level3.lvl; 35.68; killlast; wave1; 7,0; 6;
level3.lvl; 60.76; killlast; wave2; 7,0; 10;
level3.lvl; 85.97; build; splash_tower; 11,0; 190;
level3.lvl; 88.44; lifelose; wave3; 56;
level3.lvl; 88.98; lifelose; wave3; 56;
level3.lvl; 99.08; killlast; wave3; 7,0; 6;

Для каждого события пишется игровое время, время не зависит от скорости игры, то есть оно может отличаться от реального.

Таким образом, можно просмотреть как действия игрока, так и состояние игры. Это может быть важно для «синхронизации» геймплея при запуске реплея.
Например, если в реплее последний крип волны не был убит, а в логах помечено, что он погиб, то для сохранения синхронизации лучше этого крипа уничтожить искусственно.

Запись игрового времени позволяет высчитать, насколько быстро игрок реагирует на появление «раздражителя» (новой волны врагов).

Файлы реплеев записывались автоматически в файловую систему телефона, затем изымались и проигрывались в десктоп-варианте игры. Игра написана на Unity, поэтому в редакторе игра могла быть запущена так же, как и на мобильном устройстве. Разумеется, мы этим воспользовались при проигрывании реплеев.

Также по действиям игрока можно посмотреть, где в игре есть «провисание» экшн-составляющей.



Эта «карта» позволяет определить слабые места уровня, не прибегая к анализу множества отдельных реплеев, а визуальное отображение позволяет лучше «наложить» данные логов на сам уровень игры.

Таким образом, такая методика была полезна на разных стадиях проекта: как на плейтесте, где важно видеть поведение каждого из тестеров, включая «эволюцию» игрока по ходу прохождения игры, так и на более поздней стадии, когда нужно было проанализировать множество прохождений.
Tags:
Hubs:
+21
Comments 2
Comments Comments 2

Articles