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


image

Сдвиг в описании заключается в использовании техники сопрограмм. Для применения этой техники, необходимо представить, какое поведение мы ожидаем от компьютера в итоге. Поэтому я назвал небольшую библиотеку, которую создал под эту задачу — 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

Комментарии (5)


  1. Sirion
    21.01.2019 22:12

    Вступление интересное, а вот пост, по ходу, парсер съел.


  1. questor
    21.01.2019 22:13

    Черезчур кратко. Так и хочется спросить: а статья-то где?

    Не показана польза от библиотеки, можно было бы дать пример типового кода — а потом на своей библиотеке.


  1. domix32
    22.01.2019 12:25

    Демо с использованием будет?


    1. ReddogStone Автор
      22.01.2019 14:38

      Оно же есть. Линк в статье. Чуть более сложное дело тоже есть: https://jsfiddle.net/87r1weks/3


      1. domix32
        22.01.2019 22:35

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