Описание FSM

Система FSM (Finite State Machine) предназначена для централизованного управления состояниями игровых объектов, обеспечивая чёткое и последовательное выполнение действий на основе различных входящих запросов от управляющих подсистем (AI, пользовательские команды, физика и другие). Цель FSM — разрешать конфликтующие запросы и выбирать наиболее подходящее состояние объекта для поддержания логической согласованности и плавности анимаций, а также корректной работы игровых механик.

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

Основные функции FSM:

  • приём запросов от внешних управляющих систем;

  • разрешение конфликтов между запросами;

  • выбор допустимого перехода и обновление текущего состояния юнита;

  • передача состояния в другие системы: анимации, поведение, скрипты и пр.

Компоненты FSM

Состояние

Состояние (state) представляет собой описание текущей позиции или действия юнита (например: stand, walk, fire, blown_away). В каждый момент времени юнит может находиться только в одном состоянии. Состояния являются узлами в FSM-графе переходов между состояниями.

Каждое состояние:

  • имеет уникальное имя;

  • имеет как минимум один тег;

  • связи между состояниями формируют возможные переключения между состояниями.

Теги

Тег (tag) — это текстовая метка, назначаемая состоянию. Тег выполняет две функции:

  • позволяет внешним системам понять, в каком логическом состоянии находится юнит;

  • определяет, какой запрос должен привести к данному состоянию. Пример: одно из доступных состояний с тегом fire будет выбрано в ответ на запрос fire.

Запросы

Запрос (request)— это внешняя команда, поступающая от управляющих подсистем игры (AI, пользовательского ввода, физики и др.), которая инициирует в рамках FSM процесс перевода управляемого объекта в новое состояние.

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

Каждый запрос связан как минимум с одним состоянием FSM через одноимённый тег состояния. Наличие тега позволяет FSM идентифицировать, что данное состояние способно обработать указанный запрос при выполнении дополнительных условий перехода.

Теги в состояниях могут использоваться не только для связи с запросами, но и для работы других игровых подсистем.

Результат обработки запроса зависит от:

  • текущего состояния управляемого объекта;

  • приоритета запроса;

  • правил переходов, описанных в FSM-графе.

FSM поддерживает несколько типов запросов.

Таблица типов запросов приведена для ознакомления, с целью целостного восприятия работы конечного автомата (FSM) в Gem RTS.

Тип
Описание
Пример

Switch

Запрос этого типа вызывается в коде однократно и ожидает в очереди возможности для выполнения. После выполнения удаляется.

Команда “Лечь”

Job

Тип запроса, вызываемый из кода каждый квант после перевода юнита в целевое FSM-состояние. Удерживает юнита в этом состоянии, пока запрос остаётся активным. Запрос данного типа сбрасывается при отсутствии его вызова из кода дольше, чем указано в параметре duration, или при поступлении более приоритетного запроса. При сбросе запускает запрос типа Switch из блока exit в описании FSM, если юнит всё ещё находится в целевом состоянии.

Команда “Ремонтировать”

Action

Запрос данного типа вызывается из кода каждый квант до возможности перехода юнита в целевое состояние; при срабатывании переводит юнита в целевое состояние для выполнения действия, после чего удаляется. Если запрос не вызывался хотя бы один квант, то он удаляется без выполнения.

Команда “Бросить гранату”

State

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

Спрятать оружие, если оно воткнулось в стену

Система запросов и тегов используется в движке для координации работы различных игровых подсистем. Часть запросов и тегов предопределена в исходном коде. Некоторые состояния и теги могут быть определены в конфигурационных файлах (например, файлы описания элементов интерфейса, предметов инвентаря, оружия), что позволяет модифицировать и расширять поведение игровых объектов без изменений в коде, обеспечивая гибкость в настройке игровых механик.

Подмножества состояний

FSM-подмножество (Subset) — это компонент FSM, задающий ограничения на переходы, исключая из рассмотрения состояния, несовместимые с текущим состоянием объекта.

Пример Если юнит удерживает канистру, FSM-подмножество исключает состояния лежать, сидеть и ремонтировать, поскольку выполнение этих действий несовместимо с текущим состоянием объекта.

Обработка запроса в FSM

Этапы процесса обработки запроса:

  • Выбор FSM-подмножества В соответствии с текущим состоянием юнита обработчик состояний выбирает FSM-подмножество, которое ограничивает выборку доступных для перехода состояний.

  • Анализ приоритетов При поступлении нескольких запросов одновременно FSM анализирует их приоритеты. Запрос с наивысшим приоритетом имеет преимущество при выборе нового состояния. Равнозначные по приоритету запросы разрешаются согласно порядку поступления.

  • Проверка доступности перехода:

    • Задан ли графом FSM переход в целевое состояние из текущего состояния.

    • Выполняются ли условия (например, заданы соответствующие теги и/или дополнительные параметры запроса).

  • Результат обработки запроса FSM выбирает ближайшее доступное по графу состояние, соответствующее тегу запроса, независимо от того, находится ли оно в прямой связи с текущим состоянием — переключение состояний может происходить через промежуточные состояния.

Типичный сценарий работы FSM

Стартовая позиция: юнит находится в состоянии ожидания (idle). Начинается бой: юнит обнаруживает противника, получает приказ от AI атаковать врага и одновременно команду от игрока «окопаться». Рядом с юнитом происходит взрыв, взрывная волна достаточной силы, чтобы отбросить юнита и нанести ему урон. Запросы на изменение состояния юнита отправляются в FSM. Поскольку юнит не может пребывать одновременно в нескольких состояниях (окапываться, атаковать, реагировать на взрыв, лечиться или умирать), FSM разрешает этот конфликт, выбирая наиболее приоритетное и допустимое состояние.

При активации нового состояния объекта, обработчик состояний передает состояние в игровые системы, а также запускает скрипты и анимации, соответствующие этому состоянию.

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

Компоненты конфигурации FSM

Логика конечного автомата описывается в .def файле объекта с использованием блока fsm:

Формат записи

{fsm "name"
  ...
}

где "name" — имя FSM.

Описание FSM может быть вынесено в отдельный файл или каталог.

Например, в ресурсах игры Men of War II:

  • \properties\animal.ext — FSM для объекта horse;

  • \properties\human_fsm\ — FSM для объекта human.

Список запросов

Блоки request в описании FSM используется для регистрации запросов. Каждый блок соответствует одному именованному запросу и включает параметры, определяющие правила его обработки внутри FSM.

Полное описание запросов находится в исходном коде.

Структура описания запроса

{Request "name"
    {priority N} 
    {interrupt}
    {duration N}
    {exit "state_name"} 
}
Параметр
Описание

Request

Имя запроса. FSM выбирает состояние, у которого тег совпадает с указанным именем.

priority

Определяет приоритет запроса. При обработке конкурирующих запросов выбирается запрос с более высоким значением.

interrupt

Разрешает немедленный переход в новое состояние, принудительно завершая текущее, независимо от состояния активных анимаций. Опционально.

duration

Задает максимальный интервал в тактах между последовательными вызовами запроса из кода; если запрос не вызывается в течение указанного времени, он автоматически отменяется. Опционально, только для Job-запросов

exit

Задает имя состояния для автоматического перехода при отмене запроса после превышения времени ожидания, указанного в параметре duration. Опционально, только для Job-запросов

Пример описания запроса в fsm
{Request "move"
    {priority 30}
    {interrupt}
    {duration 2}
    {exit "stop-move"}
}

Блок регистрирует запрос с именем move.

При обработке запросов FSM выберет этот запрос, если все остальные поступившие запросы имеют приоритет ниже 30.

Параметр interrupt указывает, что запрос может немедленно прервать текущее состояние, независимо от завершения анимаций.

FSM будет искать состояние, у которого в параметре tag указано значение move, и осуществит переход в него при активации запроса.

Запрос остаётся активным до тех пор, пока он регулярно обновляется в коде. Если в течение двух тактов обновление не произошло (duration 2), запрос автоматически отменяется.

В случае отмены запроса FSM выполнит переход в состояние с тегом stop-move, как задано параметром exit.

Начальное состояние

Блок параметра Start используется для указания имени состояния для инициализации юнита.

Формат описания начального fsm-состояния

{Start "state_name"}

Список состояний

С помощью блоков параметра state задаются узлы графа FSM. Вложенные блоки используются для описания доступных переходов между состояниями, тегов состояний и других параметров.

Структура описания параметров fsm-состояний

{State "state_name"
    {from "source_state"}
    {fromTagged "source_tag"}
    {transit "transit_state"}
    {to "target_state"}
    {tag "name"}
    {condition "name"}
    {split "part1" "part2"}
}
Параметр
Описание

State "state_name"

Уникальный идентификатор описываемого состояния

from "source_state"

Определяет исходное состояние, из которого разрешён переход в описываемое состояние.

fromTagged "source_state"

Разрешает переход в описываемое состояние из любого состояния, имеющего указанный тег.

transit "transit_state"

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

to "target_state"

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

tag "name"

Тег описываемого состояния. Опционально может быть записано несколько строк с параметром tag для одного состояния.

condition "name"

Условие, при котором разрешён вход в это состояние, в качестве значения параметра указывается имя запроса.

split "part1" "part2"

Разделение объекта на полунезависимые части (например, "walk_all" "linked"). Используется для сложных переходов или действий, когда анимацию юнита можно разделить на анимации его частей: например, верхней и нижней частей туловища.

Пример описания fsm-состояния
{State "stand_bazooka_pick"
    {from "stand"}
    {fromTagged "up"}
    {transit "stand"}
    {to "stand"}
    {tag "up"}
    {tag "bazooka-pick"}
    {condition "knock-down"}
    {split "walk_all" "linked"}
}

Блок описывает состояние с именем stand_bazooka_pick.

Переход в это состояние разрешён из состояния stand или из любого другого состояния, у которого задан тег up.

Параметр condition указывает, что переход в состояние возможен только при активном запросе knock-down.

После завершения текущего состояния FSM автоматически выполнит переход в состояние stand, как задано параметром transit.

Также из этого состояния разрешён явный переход в stand, заданный через параметр to.

Состоянию присвоены два тега: up и bazooka-pick. Эти значения могут использоваться для сопоставления с запросами и в логике обработки состояний.

Параметр split "walk_all" "linked" указывает, что в этом состоянии применяется раздельное воспроизведение анимаций: нижняя часть тела может использовать анимацию walk_all, в то время как верхняя остаётся синхронизированной с основной последовательностью.

Подмножество состояний

С помощью блока параметра subset описываются подмножества состояний, чтобы ограничить список допустимых для выбора состояний в зависимости от текущего FSM-состояния.

Структура описания FSM-подмножества

{subset "name" from "source_subset"
  {disable "state_A"}
  {enable "state_B"}
}
Параметр
Описание

subset

Имя fsm-подмножества. Определяет набор разрешенных и запрещенных состояний для данного поднабора.

from

Имя родительского подмножества, от которого наследуются разрешённые состояния. (Опционально)

disable

Отключает доступ к состояниям, помеченным указанным тегом, в рамках данного подмножества. Может использоваться несколько раз для разных тегов.

enable

Включает доступ к состояниям, помеченным указанным тегом, в рамках данного подмножества. Может использоваться несколько раз для разных тегов.

Пример описания fsm-подмножества
{subset "with_item" from "default"
    {disable "down"}
    {disable "squat"}
    {disable "looking"}
    {disable "repair"}
    {disable "step-aside"}
    {enable "open-with_item"}
}

Подмножество с именем with_item наследует состояния подмножества default, но исключает из выборки возможных переходов состояния: лежать (down), сидеть в укрытии (squat), осматриваться (looking), ремонтировать (repair) или стрейфиться (step-aside), так как указанные состояния несовместимы с состоянием, когда юнит несет в руках тяжелый предмет, например, канистру или ящик.

Last updated