Скриптинг И.И.: Сигналы
Материал из CryWiki Russia
(→Определение, кто будет получать сигнал) |
(→Прием сигнала) |
||
(7 промежуточных версий не показаны.) | |||
Строка 1: | Строка 1: | ||
- | |||
- | |||
{{Статья|автор= AndreyFilantrop |сложность=Средняя|совместимости=All|требования= Текстовый редактор, Crysis 2 Mod SDK. |добавлена=25/04/12}}<!-- The article’s topic (AI scripting…)--> | {{Статья|автор= AndreyFilantrop |сложность=Средняя|совместимости=All|требования= Текстовый редактор, Crysis 2 Mod SDK. |добавлена=25/04/12}}<!-- The article’s topic (AI scripting…)--> | ||
Строка 35: | Строка 33: | ||
|- | |- | ||
| style="background: rgb(204, 204, 204);" width="10%" | <div style="color: rgb(0, 0, 0);">'''signal_type'''</div> | | style="background: rgb(204, 204, 204);" width="10%" | <div style="color: rgb(0, 0, 0);">'''signal_type'''</div> | ||
- | | style="background: rgb(204, 204, 204);" width=" | + | | style="background: rgb(204, 204, 204);" width="80%" | <div style="color: rgb(0, 0, 0);">'''описание'''</div> |
|- | |- | ||
| width="10%" | 1 | | width="10%" | 1 | ||
- | | width=" | + | | width="80%" | |
+ | |||
+ | сущность, получающая сигнал, будет обрабатывать его только если она активна | ||
+ | |||
и нет установки на игнорирование (см. AI:MakePuppetIgnorant более подробно) | и нет установки на игнорирование (см. AI:MakePuppetIgnorant более подробно) | ||
|- | |- | ||
| width="10%" | 0 | | width="10%" | 0 | ||
- | | width=" | + | | width="80%" | |
+ | |||
+ | сущность, получающая сигнал, будет обрабатывать его только если нет установки на игнорирование | ||
|- | |- | ||
| width="10%" | -1 | | width="10%" | -1 | ||
- | | width="80%" | сущность, получающая сигнал, будет обрабатывать его безоговорочно | + | | width="80%" | |
+ | |||
+ | сущность, получающая сигнал, будет обрабатывать его безоговорочно | ||
|} | |} | ||
Строка 80: | Строка 85: | ||
|- | |- | ||
| width="30%" | SIGNALFILTER_GROUPONLY | | width="30%" | SIGNALFILTER_GROUPONLY | ||
- | | width="70%" | Все сущности в группе | + | | width="70%" | Все сущности в группе отправителя, например враги с такой же группой id, на расстоянии коммуникации с |
отправителем | отправителем | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_SUPERGROUP |
- | | width="70%" | | + | | width="70%" | |
+ | Все сущности в группе отправителя, например враги с такой же группой id, на всём уровне | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_SPECIESONLY |
- | | width="70%" | | + | | width="70%" | Все сущности с таким же параметром '''species''' как и у отправителя, на расстоянии коммуникации с |
+ | |||
+ | отправителем | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_SUPERSPECIES |
- | | width="70%" | | + | | width="70%" | |
+ | Все сущности с таким же параметром '''species''' как и у отправителя,на всём уровне | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_HALFOFGROUP |
- | | width="70%" | | + | | width="70%" | |
+ | Половина сущностей в группе отправителя (нет способа определить какие именно сущности) | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_NEARESTGROUP |
- | | width="70%" | | + | | width="70%" | |
+ | Ближайшая сущность к отправителю в его группе | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_NEARESTINCOMM |
- | | width="70%" | | + | | width="70%" | |
+ | Ближайшая сущность к отправителю в его группе, если она в его радиусе коммуникации | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALFILTER_ANYONEINCOMM |
- | | width="70%" | | + | | width="70%" | |
+ | Все сущности в радиусе коммуникации отправителя | ||
|- | |- | ||
- | | width="30%" | | + | | width="30%" | SIGNALID_READIBILITY |
- | | width="70%" | | + | | width="70%" | |
+ | Это специальный вид сигнала, который используется чтобы заставить сущность получателя показать наглядное событие '''readability''' (звук/анимация). | ||
|} | |} | ||
+ | |||
+ | |||
+ | == Прием сигнала == | ||
+ | |||
+ | Действие, которое должно быть показано, когда получен сигнал, определяется в функции как следующая: | ||
+ | |||
+ | <source lang="lua"> | ||
+ | MySignalName = function(self, entity, sender) | ||
+ | ... | ||
+ | |||
+ | end | ||
+ | |||
+ | где | ||
+ | self: это behavior сущности | ||
+ | entity: сама сущность | ||
+ | sender: отправитель сигнала | ||
+ | </source> | ||
+ | |||
+ | Эта функция на самом деле является вызовом, который также как системные события, может быть определен в текущем поведении behavior сущности получателя, в '''default idle behavior''' - дефолтном поведении (если он не присутствует в текущем поведении behavior) или в Scripts/AI/Behaviors/Default.lua скриптовом файле (если не присутствует в дефолтном поведении). Что касается системных событий, сигнал также может быть использован, чтобы заставить персонажа '''character''' изменить своё поведение '''behavior'''; если мы добавим строчку как нижеследующая в файле персонажа character: | ||
+ | |||
+ | <source lang="lua"> | ||
+ | Behaviour1 = { | ||
+ | OnEnemySeen = *Behaviour1*, | ||
+ | OnEnemyMemory = *Behaviour2*, | ||
+ | |||
+ | MySignalName = *MyNewBehaviour*, | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Это означает, что если '''character''' на текущий момент находится в поведении «Behaviour1» и получает сигнал MySignalName, выполнив функцию вызова выше него затем переключит его поведение на '''«MyNewBehaviour»'''. | ||
+ | |||
+ | ==Пример == | ||
+ | |||
+ | |||
+ | Типичный пример это когда враг игрока замечает игрока: его «OnEnemySeen» системное событие вызывается, и давайте предположим, что он хочет известить его товарищей (товарищи с такойже группой id как у него). В этом дефолтном idle поведении (например, CoverAttack.lua если '''character''' является '''Cover'''), мы модифицируем его «OnEnemySeen» событие таким образом: | ||
+ | |||
+ | <source lang="lua"> | ||
+ | OnEnemySeen = function( self, entity, fDistance ) | ||
+ | -- вызывается когда ИИ видит живого врага | ||
+ | AI:Signal(SIGNALFILTER_GROUPONLY, 1, "ENEMY_SPOTTED",entity.id); | ||
+ | end, | ||
+ | </source> | ||
+ | |||
+ | Здесь мы определили новый сигнал называемый «'''ENEMY_SPOTTED'''». | ||
+ | Следующий шаг - определить ответную функцию. Будем считать, что другие члены группы имеют тот же character, тогда мы добавим ответную функцию в в то же idle behavior, в котором мы только что модифицировали «OnEnemySeen». | ||
+ | |||
+ | <source lang="lua"> | ||
+ | ENEMY_SPOTTED = function (self, entity, sender) | ||
+ | entity:Readibility("FIRST_HOSTILE_CONTACT"); | ||
+ | entity:InsertSubpipe(0, "DRAW_GUN"); | ||
+ | End, | ||
+ | </source> | ||
+ | |||
+ | Это заставит парней (включая и самого отправителя сигнала, который имеет такое же behavior) изменить их анимацию и произвести некоторый вид тревожного звука ('''readibility''', т.е. читабельность или наглядность), и затем достать их оружие. Обратите внимание, что измененяя его idle behavior, мы создаем дефолтный ответ по определению, который будет выполняться для любого behavior, в котором находится персонаж. В дальнейшем, мы можем захотеть переопределить этот ответ в других '''поведениях'''. Например, если мы хотим, чтобы персонаж реагировал по разному в зависимости от нахождения его в idle или attack behavior, мы добавим следующий ответ на функцию в '''CoverAttack.lua''' файле: | ||
+ | |||
+ | <source lang="lua"> | ||
+ | ENEMY_SPOTTED = function (self, entity, sender) | ||
+ | entity:SelectPipe(0, "cover_pindown"); | ||
+ | End, | ||
+ | </source> | ||
+ | |||
+ | где «cover_pindown» это голпайпа, которая заставляет парня спрятаться за ближайшим к цели укрытием. | ||
+ | Мы можем расширить это на других персонажей character: если имеется некая группа членов с разными характерами character (например, Scout, Rear и т.д.) и мы хотим заставить их реагировать также, мы должны добавить «ENEMY_SPOTTED» ответ также в их '''idle/attack''' behavior поведение. | ||
+ | |||
+ | Наконец, мы можем заставить парней переключить их поведение с '''idle''' на '''attack''', если они видят врага. Мы тогда добавим следующую строчку в '''character''' (Scripts/AI/Characters/Personalities/Cover.lua в примере): | ||
+ | |||
+ | <source lang="lua"> | ||
+ | CoverIdle = { | ||
+ | |||
+ | ENEMY_SPOTTED = *CoverAttack*, | ||
+ | }, | ||
+ | </source> | ||
+ | |||
+ | == Наследование поведения == | ||
+ | |||
+ | Если специфические сигналы должны быть использованы в более чем одном поведении '''behavior''', то существует механизм наследования. Behavior классы могут либо прямо наследовать более общую реализацию под ключевым словом '''Base = [CRYENGINE:ParentBehaviorName]''' либо непрямо, как '''Idle behavior''' персонажа так и дефолтное '''default behavior''' (определенное в файле DEFAULT.lua) рассматриваются в качестве запасного варианта поведения, если сигнал не реализован в текущем поведении '''behavior'''. | ||
+ | <br/><br/>[[Категория:Официальная документация:Crysis 2 MOD SDK:Скриптинг]] <br/> |
Текущая версия на 12:18, 28 апреля 2012
|
Содержание |
Сигналы
Краткий обзор
CryAISystem (система искусственного интеллекта CryEngine) предлагает мощный, полностью настраиваемый инструмент для коммуникации ИИ сущностей друг с другом, которым является система сигналов. Сигнал это событие, которое может быть послано агентом другому единственного агенту (включая самого себя) или под-множеству всех агентов активных в настоящее время в игре. Мы уже встречались с концептом сигнала в секции по голпайпам (см. описание сигнальной цели более подробно). В настоящей секции мы опишем:
- как посылать сигналы от поведения агента к другим агентам
- как определять подмножество агентов, которые получат посылаемый сигнал
- как агент получатель может реагировать на посланный сигнал
Посылание сигналов
Метод посылания сигналов следующий:
AI:Signal(Signal_filter, signal_type, *MySignalName*, sender_entity_id); -- смысл этой записи: -- Некий ИИ Сигнал (Фильтр сигнала, тип сигнала, *Имя моего сигнала*, id сущности посылающей сигнал)
Где:
Signal_filter: определяет подмножество агентов в игре, которые будут получать сигнал. Оно может быть выбрано из фиксированного набора символов, которые имеют префикс SIGNALFILTER_. Полный список доступных сигнальных фильтров представлен ниже.
signal_type
| описание
|
1 |
сущность, получающая сигнал, будет обрабатывать его только если она активна и нет установки на игнорирование (см. AI:MakePuppetIgnorant более подробно) |
0 |
сущность, получающая сигнал, будет обрабатывать его только если нет установки на игнорирование |
-1 |
сущность, получающая сигнал, будет обрабатывать его безоговорочно |
MySignalName: фактический идентификатор сигнала. Это может быть любая не пустая строка; должна существовать функция с таким же именем или в его текущем поведении, его дефолтном поведении (default behavior), или в DEFAULT.lua скриптовом файле для того чтобы реагировать на полученный сигнал.
entity_id: это id сущности получателя сигнала. Обычно вы можете захотеть прописать entity.id (или self.id если он вызывается из entity а не из её behavior), послать сигнал к самому отправителю, но вы также можете прописать любой другой id куда послать сигнал к другой сущности.
Определение, кто будет получать сигнал
При помощи фильтра сигнала мы можем определять подмножество агентов, которые будут получать сигнал. Параметр фильтра сигнала в вызове функции AI:Signal (...) может быть один из следующих:
Signal filter
| Сигнал посылается к:
|
0 |
Сущность определяется entity_id параметром (обычно сам посылатель но не обязательно) |
SIGNALFILTER_LASTOP |
Цель последней операции сущности (если таковая имеется) |
SIGNALFILTER_TARGET |
Текущая цель внимания сущности |
SIGNALFILTER_GROUPONLY | Все сущности в группе отправителя, например враги с такой же группой id, на расстоянии коммуникации с
отправителем |
SIGNALFILTER_SUPERGROUP |
Все сущности в группе отправителя, например враги с такой же группой id, на всём уровне |
SIGNALFILTER_SPECIESONLY | Все сущности с таким же параметром species как и у отправителя, на расстоянии коммуникации с
отправителем |
SIGNALFILTER_SUPERSPECIES |
Все сущности с таким же параметром species как и у отправителя,на всём уровне |
SIGNALFILTER_HALFOFGROUP |
Половина сущностей в группе отправителя (нет способа определить какие именно сущности) |
SIGNALFILTER_NEARESTGROUP |
Ближайшая сущность к отправителю в его группе |
SIGNALFILTER_NEARESTINCOMM |
Ближайшая сущность к отправителю в его группе, если она в его радиусе коммуникации |
SIGNALFILTER_ANYONEINCOMM |
Все сущности в радиусе коммуникации отправителя |
SIGNALID_READIBILITY |
Это специальный вид сигнала, который используется чтобы заставить сущность получателя показать наглядное событие readability (звук/анимация). |
Прием сигнала
Действие, которое должно быть показано, когда получен сигнал, определяется в функции как следующая:
MySignalName = function(self, entity, sender) ... end где self: это behavior сущности entity: сама сущность sender: отправитель сигнала
Эта функция на самом деле является вызовом, который также как системные события, может быть определен в текущем поведении behavior сущности получателя, в default idle behavior - дефолтном поведении (если он не присутствует в текущем поведении behavior) или в Scripts/AI/Behaviors/Default.lua скриптовом файле (если не присутствует в дефолтном поведении). Что касается системных событий, сигнал также может быть использован, чтобы заставить персонажа character изменить своё поведение behavior; если мы добавим строчку как нижеследующая в файле персонажа character:
Behaviour1 = { OnEnemySeen = *Behaviour1*, OnEnemyMemory = *Behaviour2*, MySignalName = *MyNewBehaviour*, }
Это означает, что если character на текущий момент находится в поведении «Behaviour1» и получает сигнал MySignalName, выполнив функцию вызова выше него затем переключит его поведение на «MyNewBehaviour».
Пример
Типичный пример это когда враг игрока замечает игрока: его «OnEnemySeen» системное событие вызывается, и давайте предположим, что он хочет известить его товарищей (товарищи с такойже группой id как у него). В этом дефолтном idle поведении (например, CoverAttack.lua если character является Cover), мы модифицируем его «OnEnemySeen» событие таким образом:
OnEnemySeen = function( self, entity, fDistance ) -- вызывается когда ИИ видит живого врага AI:Signal(SIGNALFILTER_GROUPONLY, 1, "ENEMY_SPOTTED",entity.id); end,
Здесь мы определили новый сигнал называемый «ENEMY_SPOTTED». Следующий шаг - определить ответную функцию. Будем считать, что другие члены группы имеют тот же character, тогда мы добавим ответную функцию в в то же idle behavior, в котором мы только что модифицировали «OnEnemySeen».
ENEMY_SPOTTED = function (self, entity, sender) entity:Readibility("FIRST_HOSTILE_CONTACT"); entity:InsertSubpipe(0, "DRAW_GUN"); End,
Это заставит парней (включая и самого отправителя сигнала, который имеет такое же behavior) изменить их анимацию и произвести некоторый вид тревожного звука (readibility, т.е. читабельность или наглядность), и затем достать их оружие. Обратите внимание, что измененяя его idle behavior, мы создаем дефолтный ответ по определению, который будет выполняться для любого behavior, в котором находится персонаж. В дальнейшем, мы можем захотеть переопределить этот ответ в других поведениях. Например, если мы хотим, чтобы персонаж реагировал по разному в зависимости от нахождения его в idle или attack behavior, мы добавим следующий ответ на функцию в CoverAttack.lua файле:
ENEMY_SPOTTED = function (self, entity, sender) entity:SelectPipe(0, "cover_pindown"); End,
где «cover_pindown» это голпайпа, которая заставляет парня спрятаться за ближайшим к цели укрытием. Мы можем расширить это на других персонажей character: если имеется некая группа членов с разными характерами character (например, Scout, Rear и т.д.) и мы хотим заставить их реагировать также, мы должны добавить «ENEMY_SPOTTED» ответ также в их idle/attack behavior поведение.
Наконец, мы можем заставить парней переключить их поведение с idle на attack, если они видят врага. Мы тогда добавим следующую строчку в character (Scripts/AI/Characters/Personalities/Cover.lua в примере):
CoverIdle = { ENEMY_SPOTTED = *CoverAttack*, },
Наследование поведения
Если специфические сигналы должны быть использованы в более чем одном поведении behavior, то существует механизм наследования. Behavior классы могут либо прямо наследовать более общую реализацию под ключевым словом Base = [CRYENGINE:ParentBehaviorName] либо непрямо, как Idle behavior персонажа так и дефолтное default behavior (определенное в файле DEFAULT.lua) рассматриваются в качестве запасного варианта поведения, если сигнал не реализован в текущем поведении behavior.