Лучший способ реализовать большой конечный автомат? - PullRequest
10 голосов
/ 17 июня 2011

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

Так, например:

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

Оператор switch работает, но он довольно большой и также не так легко модифицируется, как система, основанная на наследовании.

Какие-нибудь предложения по хорошо выглядящим реализациям?

EDIT: Это использует Java.

Ответы [ 5 ]

9 голосов
/ 18 июня 2011

При использовании больших конечных автоматов вы должны следить за феноменом "переходного взрыва".Оказывается, что традиционные конечные автоматы не предоставляют механизмов для повторного использования общих переходов во многих состояниях, поэтому вы в конечном итоге повторяете слишком много, и ваш конечный автомат «взрывается» (это также против «не повторяй себя» (Принцип СУХОЙ).

По этой причине я бы рекомендовал использовать иерархические конечные автоматы и методику реализации, которая позволяет легко отображать такие конечные автоматы в код.Для получения дополнительной информации об иерархических конечных автоматах см. Статью в Википедии http://en.wikipedia.org/wiki/UML_state_machine.

3 голосов
/ 17 июня 2011

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

Вы можете создать таблицу, индексированную по текущему состоянию и входу, и использовать указатель на функцию или класс функтора, чтобы представить, что происходит. Эта функция должна вернуть следующее состояние. Затем вы можете построить конечный автомат как (псевдокод):

 state := initial state
 while(state != STOP)
    state := (lookupTransition(inputs))()

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

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

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

Обновление

В Java вместо указателей на функции используйте что-то вроде класса функтора.

Другое обновление

Конечно, другой вариант - использовать компилятор конечного автомата, например Ragel .

1 голос
/ 19 июня 2012

Со своей стороны я использую stateforge HFSM (http://www.stateforge.com/). Параллельное состояние, иерархический подход и наблюдатель могут решить довольно много сложных случаев.

1 голос
/ 17 июня 2011

У Boost идеальный конечный автомат, единственным недостатком является привыкание к шаблонному / типу программирования

http://www.boost.org/doc/libs/1_46_1/libs/statechart/doc/index.html

0 голосов
/ 17 июня 2011

Не могу сказать, что когда-либо использовал его, но есть http://commons.apache.org/scxml/. Это также не так сложно писать вручную, используя подход, основанный на таблицах, предложенный другими.

...