Стандартный подход к описанию последовательности вводов пользователя и реакции на них (например при управлении персонажем в игре) — это конечный автомат (state machine). Он, однако, часто приводит к громоздким программам, понимание которых требует немалых усилий или даже зарисовок на бумаге. В этой статье я предлагаю небольшой сдвиг в описании, который позволяет экономить место на экране и мозговой ресурс.
Сдвиг в описании заключается в использовании техники сопрограмм. Для применения этой техники, необходимо представить, какое поведение мы ожидаем от компьютера в итоге. Поэтому я назвал небольшую библиотеку, которую создал под эту задачу — Behaviors.
Когда пользователь взаимодействует с программой, компьютер ждет определенного действия и реагирует на ввод определенным образом. Примитивные Behaviors и их комбинации могут заменить громоздкие конечные автоматы (state machines), которые зачастую формально или неформально встречаются в программах. К примеру, когда программа находится в состоянии ожидания нажатия определенной клавиши, можно сказать, что она выполняет Behavior waitForKey(...). Удобство в том, что Behaviors комбинируются в легко читаемой форме в отличие от конечных автоматов. Простой пример Drag&Drop:
Behavior имеет начало, конец и может возвращать значение. Behaviors исполняются по порядку или могут исполняться параллельно с помощью комбинаторов. Например комбинатор First исполняет несколько Behaviors параллельно и заканчивается, когда одно из Behaviors окончено, возвращая его результат. Forever — повторяет исполнение определенного Behavior до бесконечности. В отличии от исполнения функции, Behavior не блокирует основной поток исполнения, таким образом бесконечные Behaviors могут быть очень полезными.
Я реализовал Behaviors с помощью функций, которые получают примитивные события (как MouseDown, MouseUp, MouseMove, ...) в качестве параметра и выдают объект вида:
Реализацию можно посмотреть здесь: behavior.js на GitHubе а пример Drag&Drop здесь: jsFiddle.
Где можно применять Behaviors?
Фото: Behavior by Nick Youngson CC BY-SA 3.0 Alpha Stock Images
Сдвиг в описании заключается в использовании техники сопрограмм. Для применения этой техники, необходимо представить, какое поведение мы ожидаем от компьютера в итоге. Поэтому я назвал небольшую библиотеку, которую создал под эту задачу — Behaviors.
Когда пользователь взаимодействует с программой, компьютер ждет определенного действия и реагирует на ввод определенным образом. Примитивные Behaviors и их комбинации могут заменить громоздкие конечные автоматы (state machines), которые зачастую формально или неформально встречаются в программах. К примеру, когда программа находится в состоянии ожидания нажатия определенной клавиши, можно сказать, что она выполняет Behavior waitForKey(...). Удобство в том, что Behaviors комбинируются в легко читаемой форме в отличие от конечных автоматов. Простой пример Drag&Drop:
* DragAndDrop =
* draggedObject = ждем MouseDown на каком-то объекте
* First
* ждем MouseUp
* Forever
* ждем MouseMove
* Двигаем draggedObject
Behavior имеет начало, конец и может возвращать значение. Behaviors исполняются по порядку или могут исполняться параллельно с помощью комбинаторов. Например комбинатор First исполняет несколько Behaviors параллельно и заканчивается, когда одно из Behaviors окончено, возвращая его результат. Forever — повторяет исполнение определенного Behavior до бесконечности. В отличии от исполнения функции, Behavior не блокирует основной поток исполнения, таким образом бесконечные Behaviors могут быть очень полезными.
Я реализовал Behaviors с помощью функций, которые получают примитивные события (как MouseDown, MouseUp, MouseMove, ...) в качестве параметра и выдают объект вида:
{
done: true|false,
value: result value
}
Реализацию можно посмотреть здесь: behavior.js на GitHubе а пример Drag&Drop здесь: jsFiddle.
Где можно применять Behaviors?
- Компьютерные игры — очень удобно писать логику и ИИ, иногда даже делаю все с Behaviors, включая анимацию и передвижение объектов, но надо следить за производительностью
- Туториал во фронтенде (тур по новым функциям) — показываем информацию, ждем интеракции пользователя, продолжаем в зависимости от ввода, весь код в одном месте и читается почти как псевдокод
- Парсер предметно ориентированного языка — идиоматический код, нет необходимости «заглядывать вперед» по вводу, так как можно исполнять несколько Behaviors параллельно
Фото: Behavior by Nick Youngson CC BY-SA 3.0 Alpha Stock Images