Описание 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.

Таблица типов запросов приведена для ознакомления, с целью целостного восприятия работы конечного автомата (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:

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

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

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

Полное описание запросов доступно в исходном коде. В конфигурационный файл выносятся лишь параметры, доступные для настройки.

С помощью блоков параметра request в описание 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"}
}

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

Блок параметра 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"}
}

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

С помощью блока параметра 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