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

В этой статье я попытался смоделировать AI на основе функциональной анатомии биологической нервной системы. В чистом смысле этого слова, биологическая модель ИИ должны использовать нейронные сети для кодирования всех стимулов и двигательной реакции на обработку сигнала. К сожалению, нейронные сети все еще трудно контролировать (для игрового дизайна) и они требуют очень больших вычислительных ресурсов. Поэтому я выбрал гибридные модели, которые использует «биологическую» основу пеоедачи сигнала в сочетании с более традиционными эвристическими методами выбора цели. Главными особенностями этой модели являются:

1. Обнаружение стимула основано на интенсивности сигнала.

2. Система отбора целей, основанная на директивах, имеет известные и приобретённые цели.

3. Цели приобретаются с помощью петли обратной связи, которая управляет телом.

4. Личности ИИ построены из множества директив. Поскольку директивы являются модульными, довольно просто построить ряд отличающихся личностей. Эти личности могут демонстрировать стереотипное поведения, сохраняя достаточную гибкость для осуществления «рассуждений» и способности адаптации к уникальной ситуации. Каркас модели может быть полезен широкому кругу приложений благодаря своему общему характеру.

Немного истории

Эта модель ИИ была разработана для использования в SpecOps II, тактическом симуляторе о секретных миссиях Зеленых Беретов. Хотя акцент в проекте был сделан на реализме тактике и командном уровне, она по-прежнему подпадает под категорию шутер от первого лица. Оригинальный проект SpecOps был основан на корпусе Рейндеров американской армии. и был одним из первых «фото-реалистичных» тактических тренажеров, которые выпустили на рынок компьютерных игр. Сочетание высокого качества захвата движения, цифровых карт текстур и звуковых эффектов, записанных из достоверных источников, приводят к получению достаточно убедительного боевого опыта. Хотя в оригинальную игру было достаточно весело играть, её справедливо критикуют за бедный ИИ. Поэтому одной из основных целей для SpecOps II было улучшение алгоритма ИИ. Предыдущая логика игры и ИИ была основана на процедурных скриптах; новые системы основаны на данных, управляемых кодом ANSI C. (Мой опыт убедил меня, что управление данными кодом является более надежным, гибким и расширяемым, чем применение скриптов.) Когда структуры данных, которые управляют кодом, разработаны правильно, код сам по себе может стать очень простым.

Таблица 1. Параллели с биологической нервной системой

Функциональный блок b>Биологические системы
Блок детектирования стимула Зрительный / слуховой центры
Директивы Рефлекс / условный рефлекс
Известные / приобретённые цели Кратковременная память
Выбор цели / Навигатор Лобная кора
Направление / механизм позиционирования Моторная кора / мозжечок

 


Рис. 1. Блок-схема потока данных между функциональными блоками для этой модели мозга.

Типичное поведение в SpecOps II

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

Другая типичная последовательность может начаться, когда игрок приказывает члену отряда «уничтожить позицию». Тогда ИИ переходит к позиционированию цели, кладёт в нужное место ранец с зарядом и кричит: «File in the hole!» Директива «Уйти от взрывной волны» заставит его перейти вне опасного радиуса взрывной волны. Я наблюдал интересный случай, когда начальные маневры привели в тупик, а затем юнит вернулся к взрываемому объекту. В конце концов навигатор поместил ИИ на безопасном от взрыва расстоянии от вовремя.

Обзор потока данных

Поток данных начинается с блока обнаружения стимула, который фильтрует звуковые события и видимые объектоы и обновляет очередь известных целей. Селектор цели затем сравнивает известные и приобретённые цели личности и директивы командира, а затем выбирает конечные цели. Навигатор определяет оптимальный маршрут, чтобы добраться до позиции цели, с помощью алгоритма поиска пути. Механизм направления и позиционирования цели направляет тело, пока не будет достигнута заданная цель, а затем очередь приобретённых целей обновляется.

Структуры данных

Первичные структуры данных, используемые в этой модели мозга: BRAIN_GOAL и DIRECTIVE. ИИ персоналии представлены массивом Структур Директив и других параметров. Ниже приводится типичная декларация личности от SpecOps II:

PERSONALITY_BEGIN (TeammateRifleman)
PERSONALITY_SET_FIRING_RANGE (100000.0f)                            должно быть на расстоянии применения огнестрельного оружия (мм)
PERSONALITY_SET_FIRING_ANGLE_TOLERANCE (500.0f)         должен указать точность огня (мм)
PERSONALITY_SET_RETREAT_DAMAGE_THRESHOLD (75)       отступить, если ущерб превышает это значение  (в процентах)
DIRECTIVES_BEGIN
DIRECTIVE_ADD (TEAMMATE_FIRING_GOAL, AvoidTeammateFire, BaseWeight +1, AvoidTeammateFireDecay)
DIRECTIVE_ADD (EXPLOSIVE_GOAL, GetAwayFromExplosive, BaseWeight +1, NoDecay)
DIRECTIVE_ADD (HUMAN_TAKES_DAMAGE_GOAL, BuddyDamageVocalResponce, BaseWeight, AcquiredGoalDecay)
DIRECTIVE_ADD (DEMOLISH_POSITION_GOAL, DemolishVocalResponce, BaseWeight, AcquiredGoalDecay)
DIRECTIVE_ADD (SEEN_ENEMY_GOAL, StationaryAttackEnemy, BaseWeight1, SeenEnemyDecayRate)
DIRECTIVE_ADD (HEARD_ENEMY_GOAL, FaceEnemy, BaseWeight2, HeardEnemyDecayRate)
DIRECTIVE_ADD (UNCONDITIONAL_GOAL, FollowCommander, BaseWeight3, NoDecay)
DIRECTIVE_ADD (UNCONDITIONAL_GOAL, GoToIdle, BaseWeight4, NoDecay)
DIRECTIVES_END
PERSONALITY_END

 

Структура DIRECTIVE содержит четыре поля:

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

Структура BRAIN_GOAL содержит все необходимые данные для распознавания объектов и мер реагирования.

Поля обнаружения стимула:

  • Тип цели (т.е. видел / слышал товарищей по команде, видел / слышал врагов, услышал ружейный огонь, приобретенные цели)
  • Указатель на объект цели (void *, приводящий к указателю на тип объекта)
  • Тип позиции цели (т.е. динамические положение объекта, фиксированное положение, смещение позиции и т.д.)
  • Время обнаружения (метка в миллисекундах)
  • Ранее была известна ( true/false)

Поля реакции:

  • Действия над целью (IO_FIRE, IO_USE_INVENTORY и т.д.)
  • Скорость отклонения от траектории (градус в секунду)
  • Режим движения (вперед, вперед медленно, шагом влево, шагом право и т.д.)
  • Внутренний радиус (навигатор)
  • Внешний радиус (селектор цели)
  • Время прибытия (метка в миллисекундах, для приобретенных целей)

Блок обнаружения стимулов

Моделирование обнаружения стимулов физическим путём может достичь симметрии и помочь оправдать ожидания пользователей (то есть, если я вижу его, он должен быть в состоянии видеть меня). Оно также предотвращает AI от получения скрытого знания и несправедливого преимущества. Блок детектирования стимула моделирует силу сигнала события как порог расстояния. Например, событие HeardGunFire может быть обнаружено на расстоянии 250 метров. Этот порог расстояния может быть ослаблен рядом факторов. Если стимулирующее событие обнаружено, стимул кодируется в BRAIN_GOAL и добавляется в очередь известных целей. Эта реализация обнаружения стимулов учитывает только три сенсорные модальности: зрительные, слуховые и тактильные.

Зрительный стимул обнаружения начинается с рассмотрения всех людей и объектов в поле зрения наблюдателя (~ 180 градусов). Масштабированный порог расстояния затем вычисляется в зависимости от размера объекта, освещения, внешнего угла оси и тангенциальной скорости. Если объект находится в поле порога расстояния, выполняется ray cast для определения, есть ли препятствия между ИИ и объектом. Если все эти тесты пройдены успешно, объект кодируется в BRAIN_GOAL. Например, человек может быть закодирован в SeenEnemyGoal или объект может быть закодирована в SeenExplosiveGoal.

Поскольку встречаются в игре и звуки, они будут добавлены в звуковую очередь событий. Эти звуковые события содержат сведения о типе объекта-источника, позиции и радиусе обнаружения. Обнаружение аудио-стимулирования начинается с поиска по звуковой очереди событий для объектов в пределах порога расстояния. Этот порог расстояния может быть дополнительно сокращен внешним фактором, если луч от слушателя до источника звука обнаруживает препятствие. Если звуковое событие в поле порога расстояния, оно кодируется в BRAIN_GOAL и отправляется в очередь известных целей.

Когда очередь известных целей обновляется с BRAIN_GOAL, производится тест, чтобы определить, если она была ранее известна. Если была ранее известна — соответствующая известная цель обновляется новым временем обнаружения и местоположением. Иначе старая известная цель заменяется. Флаг PREVIOUSLY_KNOWN этой известной цели устанавливается должным образом на директивах, которые отвечают смыслу обнаруженного события.

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

Селектор цели

Селектор цели выбирает текущую цель, основываясь на директивах ответа на стимул. Грамматики для директивы строится как простой блок IF THEN:

ЕСЛИ Я обнаружил объект типа X (и вес приоритета Y — лучший) ТО вызвать функцию текущей цели Z.

Процесс выбора цели начинается с оценки каждой активной директивы для данной личности. Очередь известных или приобретённых целей затем тестируется, чтобы найти соответствия для данного типа объекта директивы. Если соответствие найдено и приоритетный вес является самым высоким в списке, то вызывается целевая функция цели. Эта функция может выполнять дополнительную логику для определения, является ли этот BRAIN_GOAL выбранным в качестве цели. Например, если AI уже вне доступного расстояния от позиции BRAIN_GOAL, могут быть выбраны альтернативные цели (например, направление). Как только текущая цель выбрана, могут быть назначены скорость, тип и направление движения к позиции цели. Безусловные директивы не требуют вызова сравнения соответствия типа объекта. Они используются по умолчанию для поведения в отсутствие известных целей.

Вес приоритет директивы может распадаться в линейной скорости в зависимости от возраста известной цели (текущее время минус время регистрации). Например, если AI в последний раз видел врага 20 секунд назад, и скорость распада директивы равна 0,01 единиц в секунду, приоритет распада: -2. Этот распад позволяет ИИ терять интерес к известным целям, которые не наблюдались некоторое время.

Селектор цели может назначить три текущих цели (направление, положение и поза) ортогонально или связанным образом. В дополнение к этим текущим целям, селектор цели можнет также выбрать пункт инвентаря и непосредственно активировать аудио ответ. При назначении направления цели, действий на целевом поле может быть множество. Например, директива стационарной атаки предполагает множество действий на целевом поле IO_FIRE. Когда механизм направлении находится в пределах порога терпимости, принимается решение о действии (т.е. выстреле). Когда позиция цели выбрана, внутренней и внешней радиус задаются директивой — внешний радиус указывает расстояние порога выбора цели для её приобретения, и внутренний радиус указывает порог расстояния, который механизм позиционирования использует для завершения движения к цели. Внутренний и внешний пороги радиусов различнаются малым расстоянии буфера (~ 250 мм), с тем чтобы предотвратить колебания на границе. Когда назначается положение цели, может быть вызвано действие над целью. Например, директива Уничтожить Объект устанавливает поле действий IO_USE_INVENTORY. Эта директива также выбирает взрывное устройство из инвентаря. Некоторые директивы могут установить положение объекта, например, директива StationaySniperAttack может установить множество положений. Также директива HitTheDirt устанавливает множество поз.

Навигатор

Как только положение цели было выбрано, навигатор должен найти путь для продвижения туда. Навигатор сначала определяет, может ли это место быть достигнуто непосредственно (то есть могу ли я идти прямо к нему?). Моя первоначальная реализация этого теста использовала ray cast из текущего положения в расположение цели. Если луч был заблокирован, то цель не имела прямого доступа. У этого метода есть две проблемы:

1. Промежуточные препятствия погут не блокировать луч, и

2. Луч может быть заблокирован плавно изогнутыми склонами, которые могут быть перейдены.

Мое последнее решение для обнаружения препятствий использует поэтапный проход. Каждый шаг (~ 500 мм) на пути к цели тестируется на препятствия. Этот метод дает надежное обнаружение препятствий и является хорошей основой для навигации по миру, состоящему из треугольников.

Если позиция цели не заблокирована миром, механизм позиционирования идет прямо к цели. В противном случае используется алгоритм поиска пути, чтобы найти альтернативный маршрут для достижения нужного места. Алгоритм поиска пути, который используется в SpecOps II, основан на узлах помощи навигации, которые размещаются в мире гейм-дизайнером. Эти узлы расположены на стыках дверей, в коридорах, на лестницах и граничных точках препятствий. Обычно есть несколько сотен узлов помощи навигации на уровне.



Рисунок 2. Вид сбоку на линейный ray cast против поэтапного обнаружения препятствий.
Первым шагом на пути процесса поиска является обновление известной очереди цели со всеми узлами помощи навигации, которые не заблокированы миром. Поскольку поэтапное прохождение через препятствие достаточно дорого по времени, тест проводится в течение нескольких кадров. После того, как очередь известных целей была обновлена с учетом узлов помощи навигации, может быть выбрана следующая позиция цели для вычисления пути. Этот выбор основан на том, когда последний раз осуществлялся расчет навигации, и как близко ИИ находится к целевой позиции. Когда механизм позиционирования достигает узла помощи навигации, он обновляет очередь приобретенных целей с учетом времени прибытия к цели. Только выбрав узлы помощи навигации, которые не были посещены, или которые имеют старейшее время прибытия, гарантирует, что путь поиска будет исчерпывающе сканировать все узлы, пока цель не сможет быть достигнута напрямую. Когда два узла помощи навигации имеют одинаковый статус и возраст, выбирается тот, что ближе к целевой позиции.

Механизм позиционирования и направления к цели

Механизмы направления и месторасположения цели берут X, Y, Z позицию цели. Эта позиция превращается в локальные координаты перемещения и вращения. Механизм направления местного двигает локальный X до расстояния 0, применяя соответствующую скорости вращения. Локальный компонент Y приводится к 0, применяя соответствующие скорости шага. Когда величина локальных X и Y координат опускается ниже целевого порогового уровня, цель «приобретена». Механизм положения цели входит в механизм направления. Когда механизм направления указывает на цель с точностью до желаемого уровня, ИИ подходит к цели с в нужном режиме движения (т.е. IO_FORWARD, IO_FORWARD_SLOW), установленом директивой. Как только расстояние до позиции цели ниже внутреннего радиус, цель «достигнута», может быть вызвано действие над целью и очередь целей обновляется. Очередь приобретённых целей используется как форма обратной связи, чтобы сказать селектору целей об их достижении. Это позволяет селектору переходить к последовательности действий.

Интерфейс Мозг / Тело

Большинство действий доводятся до тела через 128-битную виртуальную клавиатуру под названием флаги действий. Эти флаги прямо соответствуют клавишам, которые игрок может нажать, чтобы контролировать своего персонажа. Каждое действие имеет перечисленные типы для каждого бита маски (т.е. IO_FIRE, IO_FORWARD, IO_POSTURE_UP, IO_USE_INVENTORY и т.д.) Эти флаги действия затем кодируются в анимацию. Поскольку тело артикулировано, вращение регулируется отдельными скалярными полями для скорости вращения, угла вращения груди, угла наклона и вращения головы. Они позволяют частично достигать направления целей (то есть, голова и пистолет могут отслеживать врага в то время как тело движется в другом направлении).

Команды

Благодаря своей модульной структуре, директивы могут быть поставлены ИИ командиром в рантайме. Каждый мозг специальный слот для директив командующего и командной цели. Это позволяет командиру приказать одному члену команды напасть на врага, который виден только командиру. Команды могут быть отданы всей команде или отдельному члену. Обратите внимание, что очень легко создать директивы для командира ИИ, которые подвигнут его отдавать команды своим напарникам. Ниже приведен список директив командира, использующийся в SpecOps II:

TypeDirective CommanderDirectiveFormation ={ TEAMMATE_GOAL, GoBackToFormation, BaseWeight, NoDecay};

TypeDirective CommanderDirectiveHitTheDirt={ POSTURE_GOAL, HitTheDirt, BaseWeight+1,NoDecay};

TypeDirective CommanderDirectiveAttack = { SEEN_ENEMY_GOAL, ApproachAttackEnemy,BaseWeight, NoDecay};

TypeDirective CommanderDirectiveDefend = { FIXED_POSITION_GOAL, DefendPosition, BaseWeight, NoDecay};

TypeDirective CommanderDirectiveDemolish = { DEMOLISH_POSITION_GOAL, DemolishPosition, BaseWeight, NoDecay};

 

Дальнейшее совершенствование

Поскольку эта модель мозга почти полностью управляется поступающими данными, будет довольно легко заставить её учиться на собственном опыте. Например, приоритет весов для каждой директивы может быть изменен в ответ на победы или поражения. Кроме того, инструктор может опустить (уменьшить вес приоритета директивы) или подять (увеличение приоритетный вес директивы) желательность реакции на событие в игре. Реальноц проблемоц с обучением ИИ во время игры является чрезвычайно короткий жизненный цикл (10-60 секунд). Однако каждая личность могла бы иметь постоянный «мозг», который мог бы учиться в течение многих жизней. На мой взгляд, реальная стоимость динамического обучения ИИ в игре не сделает его сильным противником, но заставит постоянно менять тактику поведения. Легко сделать непобедимого противника-ИИ, реальная же цель заключается в создании ИИ, которые имеют отличительные особенности личности, и эти особенности должны развиваться с течением времени.