Введение
Привет,
меня зовут Андрей Плахов, и я работаю в компании «Nival Interactive»
ведущим программистом проекта «Silent Storm: Часовые», адд-она к проекту
«Операция Silent Storm» (
уже давно работаю не там и не над тем). Мой доклад называется «Организация
разработки AI в стратегических компьютерных играх».
Есть
некоторые разночтения в понимании аббревиатуры «AI» (искусственный
интеллект), когда речь идет об играх. Так, на прошлой КРИ читался
доклад, подготовленный Алексеем Осипенко из компании «Бука», в котором
слово AI понималось скорее в том значении, в котором в компании «Нивал»
понимаются словосочетания «игровая механика» или «игровая логика». Очень
часто к AI относят также механизмы поиска пути и следования по
найденному пути - pathfinding и pathtracking (
и правильно относят,
нечего их разделять).
В
моем докладе я этого делать не буду. Произнося слово AI, я буду иметь в
виду исключительно только механизм, при помощи которого формируются
команды, отдаваемые компьютерным игроком - то есть то, на что заменяется
input, если переходить от игрока-человека к компьютерному сопернику. И
доклад посвящен исключительно только разработке этого механизма.
В
докладе будут рассмотрены только такие стратегические игры (как
пошаговые, так и в реальном времени), в которых каждый из игроков
управляет несколькими или многими «боевыми единицами». Количество
одновременно доступных действий в рассматриваемых играх слишком велико, и
реализация дерева перебора невозможна. Для карточных игр (в том числе и
игр серии Etherlords и Magic: The Gathering), шахмат, шашек и других
подобных игр, в которых дерево перебора использовать можно, существуют
специализированные архитектуры и методы оптимизации. О них я говорить не
буду.
Довольно большая часть доклада будет посвящена опыту,
полученному в ходе проектов Silent Storm и Silent Storm: Sentinels,
поэтому я буду рад, если Вы играли в эти игры, или знаете, что они собой
представляют. Если Вы не знаете, на что они похожи, возможно, Вам
поможет перечисление аналогичных проектов: известная серия Jagged
Alliance, не менее известная серия X-Com (UFO), игра Fallout Tactics, а
также русская игра «Код доступа: Рай». Надо отметить, что игры серии
Silent Storm отличаются от вышеперечисленных большим количеством
возможностей игровой механики со сложно просчитываемыми результатами.
Например, все здания и объекты в игре могут быть разрушены. Полет пуль,
гранат, снарядов и то, видит ли один персонаж другого, просчитывается в
3d с учетом всех препятствий. Все это, естественно, приводит в том числе
и к усложнению AI.
Что будет в докладеСначала
мы поговорим о развитии архитектуры AI в проектах серии Silent Storm. В
основном речь пойдет о том, как мы ошибались, и как именно исправляли
эти ошибки. Также мы немного поговорим о том, какие сложности в
разработке и ошибки в поведении остались до сих пор, какие из них
специфичны для нашего проекта, а какие встречаются практически во всех
играх без исключения.
Хотя это изложение и само по себе может
оказаться полезным для кого-то из вас (получится карта расположения
граблей, на которые не рекомендуется наступать), основная цель этой
части в другом. Взгляд на то, как шла эволюция, помогает понять то, куда
бы она привела, если бы у проекта было бесконечно много времени на
реализацию задумок - а значит, какая архитектура стала бы идеальной.
Вот
об этой архитектуре мы и поговорим затем. Слово «идеальная», конечно,
является преувеличением. Но все же в ней собраны проверенные на практике
идеи и учтены известные нам ошибки. И, надеюсь, после предварительного
описания типичных проблем я смогу достаточно понятно изложить вам ее
основные идеи, а вы поймете, какие цели с их помощью достигаются.
Эффективная
борьба с основными трудностями невозможна, если взгляды на цели и
способы разработки AI сильно отличаются у программистов, гейм-дизайнеров
и тестировщиков игры. Поэтому я постараюсь рассказать и о том, как
построить взаимосвязи между ними для более эффективной работы. Буду рад,
если на докладе присутствуют представители всех этих профессий.
Теперь о том, чего не будет в докладеЯ
не буду рассказывать о нейронных сетях, генетических алгоритмах, цепях
Маркова и прочих принятых парадигмах самообучения. Это связано с тем,
что, по нашим данным, в компьютерных играх данные техники не оправдывают
себя - результаты, полученные с помощью них, малопредсказуемы, и не
обладают какими-либо важными преимуществами. Примерно по тем же причинам
речь не пойдет ни о языках Lisp, ПРОЛОГ (
в 2007 году я совсем не
так уверен насчет Lisp'а), ни о нечеткой логике.
Также
я не буду рассказывать о каких-то специализированных алгоритмах и
давать оценки быстродействия. Вряд ли многим из вас будут интересны
технические подробности решения задач, которые в Вашем проекте,
возможно, никогда не возникнут (
сейчас я
бы уже мог рассказать, как изложенные решения меняются с учетом жестко
ограниченной памяти и быстродействия Nintendo DS или наоборот, с учетом
нагрузки масштабной ММО - думаю, многих бы это заинтересовало).
Хотелось
бы выдвинуть вот какой тезис. Цель создателя игр - развлечь игрока.
Целью создателя игр не является выиграть у него, совершить
технологический прорыв или применить результаты своей институтской
дипломной работы. Думаю, большинство серьезных разработчиков игр это
хорошо понимают. А значит, общий и главный принцип, которого следует
придерживаться при разработке AI - продемонстрировать игроку как можно
более разнообразное (и при этом не глупое) поведение, затратив на
реализацию всех вариантов поведения как можно меньшее время, силы и
деньги.
Эволюция парадигм AI в проекте Silent Storm
Эволюция
архитектуры и основных идей AI в Silent Storm изложу достаточно кратко и
во многом упрощенно, иначе это займет слишком много времени
Просчет дерева позиций с минимаксной оценкой.
Первоначально было принято решение реализовать перебор позиций «в
глубину», как это делается в шахматных программах. От этого решения
довольно быстро отказались, т.к. количество вариантов, подлежащих
перебору, становилось недопустимо огромным уже на глубине 2. Дело в том,
что количество возможных вариантов «ходов» в Silent Storm существенно
выше, нежели в шахматах.
Просчет пар «позиция-
действие».
После этого мы перешли к просчету вариантов действий только на текущем
ходу, при этом действия выбирались на основе весовых коэффициентов,
определяемых сначала «нечеткой логикой», затем распознавателем паттернов
действий игрока, а также при помощи прочих «продвинутых» методик. При
выборе нужного действия определенный вес придавался каждой паре «позиция
– действие», и из них выбиралась пара, отвечающая наибольшему
коэффициенту, например, «бежать в точку (3:12) и кидать оттуда гранату в
точку (3,22)». Основной проблемой при использовании такой архитектуры
стала сложность реализации требований дизайнеров. Настройкой весовых
коэффициентов сложно, а иногда и невозможно реализовать правила «общего
характера». Например, для реализации правила «всегда, когда видишь
группу близко стоящих персонажей, кидай в них гранату» пришлось бы
менять коэффициенты «на лету» в зависимости от того, стоит ли часть
видимых врагов группой. А ведь есть и такие логики, как «отступить» или
«выйти из-за укрытия - выстрелить - зайти обратно», требующие
определенных действий в течение нескольких последовательных ходов. При
использовании просчета пар «позиция-действие» реализовать становилось
почти невозможно (во всяком случае, громоздко и запутанно).
Иерархия «Логики → действия».
Для реализации безусловных правил и сложных последовательностей
действий, продолжающихся несколько ходов, подбор или динамическое
изменение весовых коэффициентов - недостаточно гибкая и слишком
громоздкая техника. Поэтому было решено производить выбор действий
иерархически - сначала выбирается так называемая "логика",
представляющая собой экземпляр одного из классов, реализующих интерфейс
выбора действий, потом выбранная логика выбирает действия, либо
пользуясь просчетом пар "позиция-действие" (со своими действиями и
своими наборами коэффициентов для каждой логики), либо каким-то более
специальным образом. При этом логику можно легко запретить или
директивно заставить использовать для данного персонажа. Примерно в это
же время нам стало понятно, что использовать парадигму нечеткой логики
или реализовать какие-то алгоритмы самообучения за отведенное для
проекта время сложно и, в общем-то, не нужно.
Иерархия «Реакции → логики → действия».
Иерархия «логики→действия» решала многие проблемы, но оставалась
проблема правильной смены логик. Все «тактические приемы» (искать врага
по звуку, патрулировать, залечь, спрятаться за препятствие, использовать
стационарный пулемет и т.п.) естественно реализовать при помощи
отдельных логик. Но как в этом случае реализовать то, что персонаж
«боится», «паникует», «охраняет»? Если сделать это некоторой логикой, то
он либо не сможет использовать никакие «тактические приемы», либо нужно
где-то хранить, что после окончания логики, соответствующей данному
«тактическому приему», необходимо вновь сменить логику на предыдущую.
Естественным образом мы пришли к тому, что механизмы смены логик стали
самостоятельными сущностями, которые были названы «реакциями». Итак,
схема стала выглядеть так: реакция определяет текущую логику, которая
определяет текущие действия. При этом для вынесения общей части всех
реакций персонаж обладает «AI-состоянием», которое реализует память о
происходивших с ним событиях и хранит информацию, которая может быть
необходима всем или нескольким реакциям.
На этом этапе, в общем и целом, развитие AI в
Silent Storm прекратилось. Мы получили несколько важных уроков.
Проблемы
Главные проблемы, возникшие при разработке и тестировании AI в Silent
Storm и Silent Storm: Sentinels.
Я расскажу о них потому, что они вовсе не специфичны для наших
проектов. В той или иной степени они встречаются при разработке любой
игры стратегического жанра. И следующие части доклада будут посвящены
тому, как от них избавиться выбором правильной архитектуры AI и
налаживанием правильной технологической цепочки между программистами,
дизайнерами и тестерами.
Затрудненный tracing и bugfixing
причин, приведших к явно неверному поведению AI.
В ходе тестирования игры обнаруживается ситуация, в которой AI повел
себя глупо. Но как узнать, где ошибка? В момент ее непосредственного
проявления настоящая причина, как правило, давно осталась позади. Даже
если сохранился save с подобной ситуацией, или она может быть
воспроизведена, понять, в чем причина, бывает сложно и часто требует
часов внимательного tracing'a исходного кода игры.
Ошибочное применение логики,
пригодной только к «наиболее часто встречающимся случаям», и задуманной
для них, в нетипичных ситуациях. Это одна из главных проблем. Новые
«тактические приемы» или стратегии, придумываемые дизайнерами и
программистами, как правило, задумываются и реализуются только для
наиболее часто встречающихся ситуаций, в которых управляемый персонаж,
например, не имеет критических ранений (т.е. ограничений на действия),
вооружен типично действующим оружием, не имеет сценарных или скриптовых
ограничений и т.п. Примеры для Silent Storm: у нас возникали
«залегающие» персонажи, вооруженные ножами (если бы они убегали или
пытались атаковать, это было бы намного эффективнее – «залегание» имеет
смысл только для персонажей, вооруженных стрелковым оружием); пытались
прятаться за препятствиями водители панцеркляйнов или стрелки из
стационарных пулеметов (естественно, это у них не получалось, что
вводило AI в ступор); бывали доблестные воины, которые шли окружать
противника, не имея патронов или выжидали в засаде, несмотря на обильное
кровотечение; встречались «испуганные» юниты, которые бегали друг к
другу за помощью. В общем, значительная часть проблем с AI возникала
потому, что мы забывали указать те или иные ограничения на использование
сложных логик.
Отсутствие предсказуемости, затрудненная
реализация сценария.
При наличии разветвленной системы «реакция→логика→действие», в которой
есть несколько типов реакций, пара десятков логик и множество типов
действий, сложно предсказать, как поведут себя бойцы AI в том или ином
случае. Это сильно ухудшает предсказуемость gameplay'a на различных
зонах игры, усложняет скрипты, а также может повлиять на сценарий
неожиданным (и чаще всего абсурдным) образом. Пара примеров:
- Отважный
товарищ главного героя, по сюжету сражающийся с ним рука об руку,
наплевательски относится к своим обязанностям и сидит в подвале, думая,
что его убьют, если он выйдет наружу (хотя, согласно сюжету, главный
герой его в любом случае «спасет»).
- На определенной зоне
определенным войскам крайне сложно отдать приказ «не отходить от
стационарных пулеметов» (что требуется по задумке), так как то одна, то
другая логика все же заставляют их это сделать. Если механически
запретить им выполнять любые команды, кроме «стрелять из пулемета», но
не запретить их отдавать, такие персонажи вобще перестанут что-либо
делать (потому что, как правило, действия, которые им «хочется»
выполнить, будут запрещены).
Подобные проблемы непредсказуемости возникали и возникают
постоянно.
«Зависания» AI.
Эта проблема специфична для походовых игр (то есть, в RTS она не может
возникнуть) и заключается в том, что AI в некоторых ситуациях никогда не
отдавал команды «конец хода» (вечно удерживал ход). Типичный способ
возникновения «зависания» таков: AI отдает команду, которую unit не
может выполнить или на выполнение которой он тратит 0 action points
(action points - это игровой механизм в turn-based играх, регулирующий
максимальное количество действий, выполняемых персонажем за его ход).
Игра запрашивает следующую команду для данног unit'a. Она оказывается
той же, т.к. AI-состояние unit'a не изменилось. Так и продолжается в
вечном цикле.
Затруднена реализация совместных
действий,
или так называемого AI-генерала. Сложно даже просто реализовать влияние
разных юнитов друг на друга. Сложно решить и такую, казалось бы,
простую задачу, как «персонажи AI должны ходить одновременно, если их
действия друг другу не мешают».
Проблемы, присущие многим другим реализациям AI в играхSilent
Storm явно не является единственной игрой, при реализации AI в которой
были допущены ошибки. Достаточно вспомнить классические примеры
неверного поведения AI в других играх, даже AAA-класса. Возьмем,
например, StarCraft - возможно, лучшую игру жанра realtime strategy.
Пример повторения одних и тех же действий,
причем явно глупых (с точки зрения человеческого здравого смысла). В
Startcraft AI устраивал «беготню перед препятствием», если атакуемая
цель была скрыта за ним (вместо того, чтобы атаковать препятствие). Эта
ошибка приводила к тому, что хороший игрок-человек мог уничтожить
бесконечно много наземных юнитов противника. Также можно было видеть
бесконечную стрельба по unit'у, который сделан неуязвимым при помощи
скрипта и явно не получает от этого никаких повреждений (кстати, это
настолько распространенное поведение, что его даже не принято считать
ошибочным).
Пример применения логики в неподходящей
ситуации.
Хороший пример того, что данная ошибка неспецифична для Silent Storm -
погоня «крестьян», управляемых AI, за разведывательным юнитом вплоть до
их бесславной кончины (в StarCraft это позволяло уничтожить 4
компьютерных соперников на маленькой карте, не потеряв ни одного своего
бойца). Другой пример - строительство строения shipyard на картах,
лишенных воды (эта нелогичность встречается во многих играх).