Bender Bending

Max Payne: Искуственный интеллект персонажей

Официальное Руководство пользователя Max Payne 2 Tools

Введение

В этом разделе мы построим сеть AI-network, по которой противники смогут передвигаться и противостоять игроку, а так же напишем простейший скрипт для персонажей.
Загрузите файлы уровня используемого в материалах данного раздела AI_examples.zip
Work.lv2 является отправной точкой для данного руководств.
Result.lv2 представляет собой результат работы по окончании этого руководства.

Создание сети AI-network

Персонажи в Max Payne 2 используют сеть AI-network, вручную построенную, для ориентирования и взаимодействия с окружающей средой. Сеть состоит из узлов "AI-Nodes", соединяющихся между собой, создавая таким образом связанную сеть по всему уровню.
Так AI-nodes представлен в MaxED2
Так сеть AI-network выглядит в игре
Другими словами, если Вы хотите чтобы персонаж двигался из точки A в точку B, должна присутствовать сеть AI-network, в противном случае персонажи не будут знать, куда им можно двигаться и куда нельзя. Вы должны самостоятельно построить сеть AI-network, поместив узлы, которые автоматически свяжутся друг с другом.
Для начала работы откройте уровень "Work" этого руководства по MaxED2.
Перед созданием каких-либо персонажей, давайте сначала изготовим сеть AI-network к уровню. Чтобы это сделать, мы должны разместить узлы AI-nodes на поверхности. Давайте создадим первый узел в углу, подойдёт любой угол.
В режиме F4 разместите сетку на поверхности (SHIFT-A), переключитесь в режим F3 и укажите точку на сетке, где Вы хотите создать узел AI-node (и нажмите N - прим. переводчика).
В появившемся диалоге "New entity" выберите тип "AIN".
MaxED2 покажет Вам свойства нового созданного типа. Мы не рекомендуем менять что-либо, просто нажать OK.
На сетке появится голубй шар. Если нет - проверьте фильтр отображения - display filter (F1) для "AI-Nodes"
Это и есть узел AI-node и сеть AI-network будет рассчитана между размещенными узлами.
Для продолжения постройки сети AI-network, копируйте/вставляйте узлы AI-nodes в каждый угол из этих двух комнат и ещё по два узла по бокам дверного проёма.
После группирования узлов в комнатах (CTRL-E в режиме F5) у Вас получится нечто большее, чем просто построенная сеть AI. Если Вы экспортируете уровень в игру, Вы можете просмотреть результат конечной сети AI, нажав F8 в режиме разработчика.

Несколько слов о надлежащем размещении узлов AI

Поскольку враги вынуждены использовать сеть AI-net для поиска цели, то Вы не должны бегать вокруг по всему уровня в поисках цели, Вы не должны покидать какую-либо область на уровнях, где не наблюдается узел AI-node (иначе враги не смогут следовать за игроком должным образом). Также каждый узел AI-node может быть объединён с другим узлом AI-node образуя таким образом островки. На уровне могут быть образованы несколько независимых островков сети AI-net, но враги не могут двигаться от одного островка к другому.
Система AI-system игры Max Payne 2 взаимодействует с окружающей средой через узлы AI-nodes. Например, персонаж AI может определить в реальном времени, находится ли узел AI-nodes поблизости в укрытии от своей цели ("Cover node") или имеётся место для обстрела цели (т.е. имеется Line-Of-Fire - Линия огня, "узел LOF-node").
Может случиться, что удачным окажется решение разместить в каждом внутреннем угле, как области укрытия, узел AI-node (потому, что углы являются последним прибежищем для укрытия; по этому пути враги вероятнее всего найдут укрытие при необходимости) и постройте вокруг каждого направленного наружу узел AI-nodes.
Чрезмерное количество узлов AI-nodes в действительности не замедляют игру вообще, так что Вам не стоит волноваться об этом. Ориентация узлов AI-nodes также не влияет ни на что другое.

Несколько слов об отладке и поиске неисправностей в сети AI-Net

После создания сети AI-net, Вы заметите, что при визуализации сети AI-net в игре (F8), узлы и связующие нити иногда русуются с различными цветами. Все узлы AI-nodes в некоторых островках сети AI-net обозначены тем же цветом, так что Вы легко можете определить, связана ли одна сеть AI-net с другой. Если узлы AI-node различного цвета, то Вы будете знать, что между ними нет связи.
Если связи обозначены белым, значит сущесвует двухсторонняя связь. Если связи обозначены синим градиентом, то присутствует односторонняя связь. Яркий конец - исходный узел, более тусклый - узел предназначения. Если связи обозначены серым, то они динамически повреждены (сообщение AIN_CreateAIBlock)
При вычислении связей между узлами система создает простую Line-of-Sight - линию вида (LOS) проверки между узлами, которые найдены на той же самой высоте. Таким образом система не замечает ямы между такими узлами (и в основном Вы можете построить сеть AI-net в воздухе (на весу), если только узлы на той же высоте) и рекомендуется использовать материал категории AI_Node_Collision_Nodraw для постройки геометрии между такими узлами. Этот материал может использоваться для постройки геометрии, с которой вычисление связи узла AI-node обращается как стереометрия, но это не будет экспортировано в игру. Который также означает, что Вы можете строить мосты с AI_Node_Collision_Nodraw, создавая сети AI-nets поверх ям.
Для узлов, которые находятся на разных высотах, система производит сложные вычисления для проверки, смогут ли персонажи фактически перемещаться от одного узла к другому. На практике это означает, что ямы, упомянутые выше, также будут приняты во внимание, слегка приподнимая узлы с другой стороны ямы.
Для постройки сети AI-net, которая заставляет врагов спрыгивать с выступов, рекомендуется разместить узлы AI-nodes прямо на краю и другой узел AI пониже.
Максимальная высота для вертикальной связи AI-connection 5 метров. Так же и с длинными лестницами, где Вы должны размещать узлы AI-nodes по лестнице, при этом вертикальная длина между узлами не должна быть больше 5 метров. Иначе узлы просто не будут соединяться. Также настоятельно рекомендуется дополнить всю лестницу персонажами, сталкивающими слайды (Вы можете использовать материал категории CharacterCollision_Nodraw).
Динамические Объекты не принимаются во внимание при вычислении сети AI-net и всех проходов связей через них. Если Вам необходимо блокировать связи через ДО, то Вам необходимо закрыть связь динамически или построить отдельный объект AI_Node_Collision_Nodraw.
Также узлы проверяют связь только против узлов, которые расположены в той же комнате или в соседних комнатах. Т. е. никакая связь не будет проходить через два выхода, что означает, что каждая комната должна иметь по крайней мере один узел, если Вы хотите, чтобы персонажи AI-characters смогли пройти через.

Создание персонажа

Теперь, когда мы имеем сеть AI-net, мы можем создать первого врага на уровне. Снова разместите сетку на плоскости, в желаемом месте пометите курсор в режиме F3 и нажмите "N". В диалоге "New entity" выберите тип "Enemy". Не имеет значения, если персонаж не находится на дорожке сети AI-Net, пока тот не имеет прямого выхода к узлу AI-node.
В окне "Entity properties" нам нужно пока только выбрать вражеский скин-"skin". Все различные враги Макса Пейна 2 могуть быть выбраны в ниспадающем списке в разделе "Skins". Давайте выберем для курса обучения C03_Russian_A.
ПОДСКАЗКА: Обычно хорошим решением является переименование каждого нового типа - entity, так как это будет иметь FSM с чем-нибудь that You find descriptive. Поскольку сложность Вашего уровня будет повышенная, то Вам не обязательно называть каждого персонажа "Enemy_XX"
На плоскости появится шар, обозначающий местоположение точки старта врага. Если нет - проверьте фильтр отображения - display filter (F1) для "Keypoints"

Контролирование AI

По умолчанию, персонажи фактически не будут совершать какие-либо действия. Мы должны ещё командовать при помощи мини-боевой тактики. Мы можем осуществить это посредством мессаджа под названием "AI_SetTactic", который использует наименование тактики в качестве параметра. И так, откройте диалог FSM для врагов (выберите врага и нажмите "B" в режиме F5) и к событию "Startup" добавьте:
This->AI_SetTactic( Combat );
Теперь экспортируйте в игру и персонаж сразится с Максом.

Несколько слов о вражеских группировках

В окне свойств типов Вы можете видеть в ниспадающем списке диалог под названием "Group". Это относится к системе, которую Вы можете использовать для объединения многочисленных врагов в группы, где их восприятие чуств будет разделено и при установке цели они могут быть упомянуты в названии группы. Вы можете добавлять и управлять группами кнопкой "Edit groups". Группа под названием "PLAYER_GROUP" зарезервирована для создания персонажей AI-characters, принадлежащих к группировке самого игрока.

Несколько слов о контролировании AI

Если Вы хотите свободно протестировать управление AI, некоторые рекомендации для команд:
AI_SetTarget( Target );
• Устанавливает боевую цель для персонажа AI-character.
• Присваивает имя персонажа, FSM, триггера, DO или групповой номер как параметр.
• Специальные имена целей:
Player - по умолчанию
Enemies - относится ко всем персонажам, чья цель установлена на "player" т.е. враги игрока.
AI_SetTargetGroups( Target1, Target2 );
• Устанавливает две боевые цели для персонажа AI-character.
• Присваивает имена групп как параметры
AI_SetTactic( Name );
• Устанавливает боевую тактику для персонажа AI-character. Тактика определяет поведение AI-behavior и трудно-закодированность - hard-coded.
• Присваивает имя тактики как параметр
Combat - Стреляет по цели с места и когда цели бегут к узлам AI-Node с линии огня - Line-of-fire (LOF) - к цели..
Cover - Пытается прикрывать в беге, прикрывая узел.
CoverCombat - Стреляет по цели и периодически ищет укрытие
Follow - Следует за игроком не сражаясь. Удобен в использовании с дружественными NPC.
FollowCombat - Следует за игроком и в то же самое время сражается против его же целей. Должен использоваться с целью, установленной на врагов - "Enemies"
GuardCombat - Подобен CoverCombat, но не следует за целью слишком далеко, вместо этого остаётся в помещении.
"Idle" - Stands idle. Это по умолчанию.
AI_RevealTarget();
• Вынуждает персонажа становиться бдительным и начать охотиться на цель.
AI_EnableHearing( true/false );
AI_EnableSeeing( true/false );
AI_EnableFeeling( true/false );
• Установки "True" или "False" для различных сенсорных систем персонажей.
• Везде по умолчанию "True".
AI_ResetOnActivate();
• Повторно устанавливает событие OnActivate в его изначальное состояние.
• OnActivate является случайным, который имеют все персонажи в своих FSM, и посылается только единожды, когда они почувствуют свою цель впервые. Это сообщение может использоваться для повторной установки события OnActivate так, чтобы оно было послано при восприятии цели в следующий раз.
AI_EnableVoiceEvents( true/false );
• Может быть использован для запрещения автоматического крика врагов.

Управление инвентарём

Здесь описаны средства управления инвентарными запасами врагов.
C_RemoveAllWeapons( weapon ) ;
• Удаляет всё оружие кроме определённого как параметр, которое немедленно появится в руке и получит бесконечный боезапас.
• Присваивает наименование оружия или "empty" как параметр.
C_RemoveAllWeaponsMelee( weapon );
• Удаляет всё оружие кроме определённого как параметр, которое немедленно появится в руке. Не пополняет никакой боезапас.
• Присваивает наименование оружия или "empty" как параметр.
C_PickupWeapon( weapon );
• Добавляет оружие в инвентарь персонажа. Без боезапаса.
• Враги будут автоматически использовать наиболее мощное оружие с боезапасом из инвентаря.
C_PickupAmmo( weapon , amount );
• Добавляет боезапас в инвентарь персонажа.
C_SetInfiniteAmmo( weapon, true/false );
• Устанавливает бесконечный боезапас для оружия
P_CreateProjectileToBone ( ProjectileName, Amount, Bone );
• Бросает метательные снаряды (projectile) от кости врага. Удобен для выбрасывания гранат и болеутоляющих из карманов убитых врагов. Метательные снаряды могут быть подняты с префиксом "Enemy_". К примеру;
This->P_CreateProjectileToBone ( Enemy_Painkiller, 1 , "Bip01 L Gun");
бросит болеутоляющее от левой кости - gunbone - врага. Наименование кости находится в кавычках потому, что включает пробел.

Скрипты персонажей

Вы также можете вручную написать скрипты для персонажей для обыгрывания каких-либо ситуаций. В основном система скриптов работает так, чтобы Вы могли послать последовательность команд персонажу, который отложит их и будет выполнять их один за другим. Например, Вы можете задать команду скриптом персонажу идти в определённый пункт - waypoint, затем анимация - animate, присесть и стрелять.
Здесь приведены краткие описания команд.
AI_AddCommand( Move, Act, Parameters );
• Добавляет скриптовую команду. Последовательные команды добавлены к скриптовой массе.
• Третий параметр должен содержать пустые кавычки, если не используется
AI_PushCommand( Move, Act, Parameters );
• Выдвигает скриптовую команду как первый пункт массы, исполняется незамедлительно.
• Третий параметр должен содержать пустые кавычки, если не используется
Действующие скрипты для вышеприведённых команд
:MOVE ACT PARAMETERS
Stand - Стоять на месте. Эта команда бесконечно долгая, так что масса скрипта не будет продвигаться самостоятельно после этой команды.Nothing / Aim / LookAt / LookAtPlayer / Shoot / Reload / Throwgrenade / Throwmolotov-
Crouch - Приседать на месте. Эта команда бесконечно долгая. Nothing / Aim / LookAt / LookAtPlayer / Shoot / Reload-
Walk - Идёт к waypointNothing / Aim / LookAt / LookAtPlayer / ShootАбсолютное имя в иерархии waypoint'ов. Например: "::room::waypoint1"
Run - Бежит к waypointNothing / Aim / LookAt / LookAtPlayer / Shoot Абсолютное имя в иерархии waypoint'ов. Например: "::room::waypoint1"
Animate - Исполняется анимация всего тела - full-bodyNothing / Lookat / LookAtPlayerИмя анимации full-body
AnimateNoBlend - Исполняется анимация full-body без смешения начала и конца. Nothing / Lookat / LookAtPlayerИмя анимации full-body
AnimateLooping - Исполняется анимация full-body в цикле. Эта команда бесконечно долгая. Nothing / Lookat / LookAtPlayerИмя анимации full-body
AnimateLoopingNoBlend - Исполняется анимация full-body в цикле, без смешения начала и конца. Эта команда бесконечно долгая. Nothing / Lookat / LookAtPlayerИмя анимации full-body
SubAnimate - Исполняется дополнительная анимация - sub-animation.Nothing Имя анимации Sub-animation
DodgeBackwardNothing / LookAt-
DodgeForwardNothing / LookAt-
DodgeLeftNothing / LookAt-
DodgeRightNothing / LookAt-
ShootDodgeBackwardNothing / LookAt-
ShootDodgeForwardNothing / LookAt-
ShootDodgeLeft Nothing / LookAt-
ShootDodgeRightNothing / LookAt-
FSMSend - Специальная команда для включения события по умолчанию из массы скрипта.Nothing Имя события по умолчанию
Подробно о команде "Act"
Aim - Цель задачи к цели (или туда, где есть цель, как думает AI)
LookAt - Ориентируется на цель (или туда, где есть цель, как думает AI)
LookAtPlayer - Ориентируется на игрока
Shoot - Стреляет в цель, если есть линия огня - LOF
Reload - Пережаряжает
ThrowGrenade - Бросает гранату (если есть в инветаре)
ThrowMolotov - Бросает молотов (если есть в инвентаре)
Обратите внимание, что вышеуказанные скрипты предназначенны для "модернизации сил" персонажей, кроме STAND, CROUCH и ANIMATELOOPING, для которых Вы должны использовать команду вручную "C_ForceUpdate( time );"
AI_AddPatrolCommand( Waypoint, Waypoint, Waypoint );
• Та же самая функция что и AI_AddCommand за исключением того, что требуется три waypoint'та как параметр. Тогда персонаж патрулирует вокруг этих waypoint'ов.
AI_PushPatrolCommand( Waypoint, Waypoint, Waypoint );
• Та же самая функция что и AI_PushCommand за исключением того, что требуется три waypoint'та как параметр. Тогда персонаж патрулирует вокруг этих waypoint'ов.
AI_StopScripting();
• Освобождает массу скрипта и входить в поведение AI-тактика.
AI_EnablePerceiving( true/false );
• Это очень важное сообщение. Скрипт персонажа работает так, что враги остановят их скрипт, как только они почувствуют свою цель. Так в случае, где Вы захотите, чтобы персонаж исполнил скрипт без прерываний, Вы должны запретить сенсорную систему - sensory systems - персонажа. Вы можете сделать это прежде, чем будут упомянуты сообщения AI_EnableHearing / Seeing / Feeling, но в большинстве случаев гораздо легче использовать специальную команду AI_EnablePerceiving( false );, которая блокирует все сенсорные системы независимо от их состояния, в течения действия скрипта. Когда AI возвращается к тактики поведения, AI_EnablePerceiving автоматически возвращает истину - true, и сенсорные системы ведут себя как прежде.
Перед дальнейшим каким-либо движением, давайте добавим простой массив скрипта к нашему персонажу в учебном уровне. На уровне существует небольшое скопление взрывчатых веществ, поэтому нам бы хотелось, чтобы персонаж изначально стремился к двери и при обнаружении игрока спрятался в груду взрывчатых веществ для укрытия.
Сначала давайте поместим персонаж в удобное место, приблизительно в 4-5 метрах от взрывной груды, ориентированной к дверному проёму.
Нацелив персонаж к двери при запуске, мы добавим пару сообщений к событию StartUp, что будет выглядеть следующим образом:
Короче говоря, мы запретили слышимость так, чтобы враг не выпал из скрипта если игрок наделал шума в предыдущей комнате, и мы добавили скрипт-команду на исполнение анимации.
Событие OnActivate является событием, которое вызывается, когда персонаж почует свою цель впервые, так что мы используем скрипт уклонения в укрытие. Это должно выглядеть следующим образом:
Мы снова запретили восприятие, поскольку мы хотим, чтобы враг исполнил скрипт и мы добавим скрипт уклонения влево. Мы также разрешили слух (прислушиваться назад), хотя это фактически не повлияет на поведение в течение этого скрипта (т.к. всё восприятие блокировано так или иначе), но в этом случае враг слышит после исполнения скрипта.
Несколько слов о закодированных событиях для персонажей:
Другие закодированные события для персонажей вызваны следующим;
OnDeath - Когда персонаж умирает
OnLowHealt - Когда здоровья меньше 50-ти процентов
OnPlayerAttack - Когда игрок атакован
OnUse - Когда будучи "управляемым" игроком
Теперь Вы можете экспортировать и протестировать в игре. Также протестируйте персонаж на наличие информации отладки AI (нажмите F7 в игре в режиме разработчика). Информация отладки отображается прямо над персонажем в игровом мире. Выглядит это наподобие этого:
**(20:6) ::Big_Room::Character_00.AI
Target player AP[PSHF]
Script : ANIMATELOOPING, NOTHING, index 522**
Информация:
• (20:6) - Числовой индекс персонажа AI, назначается в процессе выполнения и может использоваться для обращения к AI во время игры через консоль. Например: 20:6->AI_EnableVisualization(True);
::Big_Room::Character_00.AI - Полное наименование иерархии персонажа AI
Target player - Цель врага - игрок
AP[PSHF] - Alerted state - готовность "номер один"/ Perceiving target - восприятие цели[ Perceiving enabled - разрешение восприятия / Seeing enabled - разрешение наблюдения/ Hearing enabled - разрешение слышимости / Feeling enabled - разрешение чувствительности] (отображается как "-" если передающий флаг запрещён)
Script : ANIMATELOOPING, NOTHING, index 522 - Скриптовая масса, имеющая только один пункт в этом примере. Числовой индекс - внутренний индекс номера анимации, выполняемой персонажем.

Несколько слов об отладке AI

Здесь содержится информация отладки AI, которая может оказаться полезной; Вы можете убрать информацию о состоянии персонажа AI сообщением AI_Dump. Требуется наличие суффикса .AI на приёмник, т. к. это посылается компоненту персонажа AI-component, например:
::Room::e1.AI->AI_Dump();
Вы также можете убрать непосредственно готовность персонажа C_Dump. Это вообще не требует суффикса. Например:
::Room::e1->C_Dump();
И Вы можете включить небольшую визуализацию AI послав AI_EnableVisualization( true ); компоненту AI. Например:
::Room::e1.AI->AI_EnableVisualization( true );
Персонаж может видеть свою цель, поскольку его линия вида -line-of-sight - приняла значение true (правая жёлтая линия. Она тускнеет, когда линия вида - LOS - имеет значение false), но не может стрелять если линия огня - line-of-fire - имеет значение false (серая линия). Окрашена в ярко-белый цвет, если LOF имеет значение true). Он бежит по синей линий.
Ярко синий шар обозначает место, где, как думает персонаж AI, находится его цель, а тусклый то место, как решила система AI, куда персонаж должен бежать, чтобы стрелять по цели. Сейчас это касается бегущего.

Заключительные слова

Теперь Вы должны быть достаточно экипированы для того, чтобы построить свои собственные боевую и скриптовую сцены. В заключение, давайте ещё раз вспомним, что персонаж игрока также имеет AI, если только Вы не запретили контроль управления игрока - MaxPayne_GameMode->GM_SetPlayerControls( False ); у Вас должен быть игровой персонаж с боевой системой AI и заскриптованный точно также, как и любой другой персонаж в игре.
Также обратите внимание на то, что сеть AI, построенная в обучающей программе, редка для того, чтобы действительно работать безупречно. У Вас не должны быть очень большие расстояния между узлами AI-nodes. Даже тогда я не рекомендую заполнять пустую комнату большим количеством узлов AI-nodes, когда Вы намереваетесь добавить любую геометрию в комнаты, которые должны быть приняты в сеть AI-net, поскольку Вы будете добавлять больше узлов позже так или иначе, и этот путь не станет легко проходимым.
Если Вы не можете достичь желаемого поведения при построении сцен с привлечением вражеских групп, скриптования и OnActivate, то вот детальная информация о поведении группы OnActivate при использовании AI_EnablePerceiving:
• Вражеский флаг "Тревога" - "Alert" - установлен, когда цель опознана (или показалась)
• Враги охотятся на Вас по своей тактике, когда они "alert"
OnActivate посылается, если цель опознана (но не когда показалась)
• Опознанная цель разделяется на группы
• Враг может быть "alert" без будучи посланной OnActivate
AI_EnablePerceiving( False ); блокирует восприятие цели, в оба и вне
• Флаг тревоги - alert - устанавливается на персонажа, когда он видит цель, даже если глаза закрыты (Alert никогда не вещает на группу, только OnActivate, который будет установлен в наборе с флагом Alert flag on to the rest)
Несколько дополнительных сообщений, которые могут оказаться полезными:
AIN_CreateAIBlock( radius );
• Блокирует все связи узлов в радиусе
AIN_RemoveAllBlocks();
• Удаляет все узлы блоков, созданные приёмником
DG_CreateDanger( radius, time, BoolExplosion );
• Создаёт опасность, от которой все враги обращаются в бегство
• Если это опасность взрыва враги только укрываются от эпицентра взрыва, даже если они находятся в пределах радиуса
DG_RemoveAllDangers( );
• Удаляет все опасности от приёмника
C_Hide( true/false );
• Может использоваться для того, чтобы скрыть персонажа (полностью замораживает). Когда не спрятанный персонаж продолжает выполнение вообще
• Почти каждый враг в Max Payne 2 фактически скрыть при запуске и появляется только тогда, когда игрок приближается к области, где он находится и гарантировано враги не будут приведены в готовность слишком рано

Просмотров: 2 314

Это сообщение удалено