Machine — различия между версиями

Материал из wiki.appsalutecreator.com
Перейти к: навигация, поиск
(draw)
(phys)
Строка 194: Строка 194:
 
* break - прервать команды - Прервать выполнение команд phys на этой команде (запустить их сново можно из команд процессов).  
 
* break - прервать команды - Прервать выполнение команд phys на этой команде (запустить их сново можно из команд процессов).  
  
Если указаны целевая скорость или целевая координата, начальные скорости по соответствующим компонентам подправляются так, чтобы выйти на заданные целевые значения.
 
 
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.
 
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.
 
<pre>
 
<pre>

Версия 11:49, 21 января 2013

Машина состояний (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.

Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё

Общие параметры

(см. описание Object)

Параметры

  • Состояние - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.
  • Хранить нажатость - нужно ли сбрасывать нажатость при изменении состояния.
  • res - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).
  • states - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.
  • прокликиваемая - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.

Действия

Инициализация

При первом попадании в состояние, сразу выполняются команды инициализации init, draw и set. Если в этих командах нет параметра break, они все выполняются до запуска процессов.

draw

Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:

  • res - ресурс картинки (перетаскивается из редактора ресурсов)
  • f - начальный кадр
  • ft - длительность кадра в миллисекундах
  • loop - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз
  • go - перейти в состояние
  • if - условие перехода
  • break - прервать команды

Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.

Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет данный draw (даже если он непервый).

Для работы loop необходимо чтобы в редакторе ресурсов в настройках анимации было отключено зацикливание(looped).

init

Инициализация параметров данной машины

  • x,y - координата точки пивота относительно сцены или родительского объекта;
  • sx,sy - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);
  • ang - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;
  • v - скорость для команды move
  • vr - угловая скорость для команды rot
  • vx,vy - начальная скорость для команды phys
  • ax,ay - ускорение для команды phys
  • z координата - Координата машины по z.
  • z прирощение - Прирощение координаты машины по z относительно текущего.
  • vis - видимость - Видимость машины
  • показать рейтинг - Значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга
  • закрыть приложение - Значение 1 означает, что при выполнении этого инита приложение будет закрыто
  • перезагрузить лэйаут - Значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут
  • вернуться назад - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран
  • реклама AdMob - 1 - показать, 0 - спрятать, -1 - не изменять состояние
  • прокликиваемая - Если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше
  • курсор - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.

Так же, как и при инициализации картинки (draw), вызов команды (init) переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений

set

Перевод другого объекта в некоторое состояние или изменение его параметров.

  • obj - изменяемый объект (выбирается из списка объектов);
  • st - состояние в которое переводится объект.
  • scr_obj - У какого экрана надо изменить состояние st либо параметры.
  • par - Параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.
  • val - Значение параметра объекта для установки
  • round - Округлить значение, записываемое в val
  • val_obj - id объекта, будет записано в в par
  • val_txt - id текста, будет записано в в par
  • val_scr - id экрана, будет записано в в par
  • var - Имя переменной данной машины, значение которой присваивается в параметр par объекта obj
  • scr - Экран на который мы хотим перейти
  • user - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется
  • if - Номер (начиная с нуля) команды if при выполнении которого происходит отработка команды set. Возможно использование логических выражений.
  • break - Прервать выполнение команд set на этой команде (запустить их сново можно из команд процессов).

Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.

Совершение внутриигровой покупки

совершить in-app покупку - При переходе в состояние открывается системное окно с предложением совершить in-app покупку.

id покупки - Внутренний id покупки для приложения, указывается в объекте store
объект(успех) - Объект, которому сообщается об удачной покупке
состояние(успех) - Состояние в которое переводится выбранный объект в случае успешной покупки
объект(провал) - Объект, которому сообщается о неудачной покупке
состояние(провал) - Состояние в которое переводится объект в случае неудачной покупки

Процессы

wait

Пауза имеет следующие параметры:

  • t - длительность выполнения команды в ms
  • dt - интервал t+/- dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае)
  • p - вероятность срабатывания перехода в состояние, указываемое параметром go.
  • go - состояние, в которое нужно перейти поле окончания времени и срабатывания условия if, если оно указано.
  • if - номер команды if.
  • loop - зациклить команды
  • break - Прервать выполнение команд wait на этой команде (запустить их сново можно из команд процессов).

Кроме этих параметров, все команды процессов могут содержать параметры break, loop и параметры совпадающие с именами других процессов move,rot и т.д. Все эти параметры служат для управления циклами и прерываниями.

Простейший набор параметров команды wait выглядит следующим образом:

<wait t="1000" go="next"/>    // ждем 1000ms и покидаем состояние

Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):

<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1
<wait go="st2"/> // иначе,  перейдем в st2

Этот же синтаксис позволяет делать состояния с различным временем жизни:

<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms
<wait t="100" go="next"/>       // или 200ms

Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:

<wait t="1000" dt="200" go="next"/>

move

Перемещение по сцене:

  • tx, ty - целевые координаты в пикселях, к которым должен переместиться объект
  • dx, dy - величина смещения от текущей (если есть - tx,ty игнорируются). Можно задавать смесь tx, dy или dx,ty
  • v - скороcть перемещения в пикселях в секунду. Для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость.
  • t - время перемещения (v игнорируется)
  • go - новое состояние - Состояние в которое нужно перейти после окончания времени.
  • if - условие перехода - Номер (начиная с нуля) условия перехода (команды if). Возможно использование логических выражений.
  • loop - зациклить команды - Начать выполнение команд движения с первой команды.
  • break - прервать команды - Прервать выполнение команд move на этой команде (запустить их сново можно из команд процессов).

В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.

Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)

rot

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

  • ta - целевой угол поворота объекта
  • da - на сколько надо повернуться (ta игнорируется)
  • v - угловая скорость поворота в градусах в секунду
  • t - время поворота (vr игнорируется)
  • go - новое состояние - Состояние в которое нужно перейти после окончания времени.
  • if - условие перехода - Номер (начиная с нуля) условия перехода (команды if). Возможно использование логических выражений.
  • loop - зациклить команды - Начать выполнение команд движения с первой команды.
  • break - прервать команды - Прервать выполнение команд rot на этой команде (запустить их сново можно из команд процессов).

Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.

alpha

Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)

  • ta - целевая прозрачность
  • da - на сколько надо изменить прозрачность от текущей (ta игнорируется)
  • v - скорость изменения прозрачности (в долях единицы в ms)
  • t - время изменения (v игнорируется)
  • go - новое состояние - Состояние в которое нужно перейти после окончания времени.
  • if - условие перехода - Номер (начиная с нуля) условия перехода (команды if). Возможно использование логических выражений.
  • loop - зациклить команды - Начать выполнение команд alpha с первой команды.
  • break - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их сново можно из команд процессов).

scale

Изменение размеров объекта

  • tx, ty - целевой масштаб по каждой оси
  • dx, dy - на сколько изменить масштаб по каждой оси
  • v - скорость изменения масштаба (в долях единицы в сек.)
  • t - длительность выполнения команды (v игнорируется)
  • go - новое состояние - Состояние в которое нужно перейти после окончания времени.
  • if - условие перехода - Номер (начиная с нуля) условия перехода (команды if). Возможно использование логических выражений.
  • loop - зациклить команды - Начать выполнение команд scale с первой команды.
  • break - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).

phys

Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).

  • vx, vy - начальная скорость
  • ax, ay - величина ускорения по каждой оси
  • tvx, tvy - целевая скорость
  • tx, ty - целевая координата
  • go - новое состояние - Состояние в которое нужно перейти после окончания времени.
  • if - условие перехода - Номер (начиная с нуля) условия перехода (команды if). Возможно использование логических выражений.
  • loop - зациклить команды - Начать выполнение команд phys с первой команды.
  • break - прервать команды - Прервать выполнение команд phys на этой команде (запустить их сново можно из команд процессов).

Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.


<st id="down">                                    // падаем
    <phys vy="0" ay="20" ty="0" go="touch"/>
</st>

<st id="touch">                                   // касаемся земли
    <move dy="24" t="300"/>                       // опускаем центр при сжатии
    <scale ty="0.8" t="300"/>                     // сжимаемся
    <move dy="-24" t="300"/>                      // поднимаем центр при разжатии
    <scale ty="1" t="300" go="up"/>               // разжимаемся
</st>

<st id="up">                                      // взлетаем
    <phys vy="0" ty="-200" go="down"/>
</st>

Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.

Воздействия

click

Команда вызывается, если на объект кликнули мышкой

  • go - состояние в которое при клике надо перейти;
  • if - номер команды условия перехода.

touch_in

touch_in - наведение мыши/пальца на машину

  • go - состояние в которое при клике надо перейти;
  • if - номер команды условия перехода.

touch_out

touch_out - выведение мыши/пальца из машины

  • go - состояние в которое при клике надо перейти;
  • if - номер команды условия перехода.

mouse_in

touch_in - наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)

  • go - состояние в которое при клике надо перейти;
  • if - номер команды условия перехода.

mouse_out

touch_out - выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)

  • go - состояние в которое при клике надо перейти;
  • if - номер команды условия перехода.

drag

Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Параметры команды:

  • x1 - разрешено таскать, когда координата объекта правее;
  • x2 - разрешено таскать, когда координата объекта левее;
  • y1 - разрешено таскать, когда координата объекта ниже;
  • y2 - разрешено таскать, когда координата объекта выше;
  • if - номер команды условия разрешения таскания.
  • obj - объект - У какого объекта надо изменить состояние
  • st - его новое состояние - На какое надо изменить состояние объекта
  • таскать за пивот - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили

drop

Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop

  • obj - объект, на который надо уронить таскаемый объект;
  • go - состояние в которое переходим при отпускании мышки;
  • if - номер условия разрешения бросания.

Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:


<st id="drag">
    <drag x1="-350" x2="350" y1="-250" y2="250"/>
    <drop obj="box" go="open"/>
</st>

<st id="open">
    <set obj="box" st="open"/>
    <scale tx="0.01" ty="0.01" t="500" go="hide"/>
</st>

<st id="hide">
    <init x="268" y="30"/>
    <scale tx="1" ty="1" t="500" go="drag"/>
</st>


Ящик:


<st id="close">                        // начальное состояние ящика
    <init al="1"/>                     // если его кто-то сюда переведет - он появится.
</st>

<st id="open">              
    <alpha ta="0" t="500"/>            // исчезает по прозрачности за 500 ms
</st>

throw

Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:

  • go - состояние, в которое, при клике, надо перейти.
  • if - номер команды разрешения бросания.
  • force - Получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.

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

apply

Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys.

  • obj - сработает , если пересеклись с этим объектом;
  • x1 - сработает, если центр объекта левее этого x-ка;
  • x2 - сработает, если центр объекта правее этого x-ка;
  • y1 - сработает, если центр объекта выше этого y-ка;
  • y2 - сработает, если центр объекта ниже этого y-ка;
  • rm - радиус этой машины (если rm=0, то она считается прямоугольной)
  • ro - радиус объекта obj (если ro=0, то он считается прямоугольным)
  • st - состояние, в которое надо перевести объект obj
  • go - состояние, в которое надо перейти при срабатывании;
  • if - номер команды разрешения применения.

Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":


<st id="trow">
    <init x="-350" y="150"/>                      // начальное положение
    <throw go="fly"/>                             // бросаем
</st>

<st id="fly">
    <phys ay="100"/>                              // летим
    <apply y2="300" go="throw"/>                  // с землей
    <apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой
</st>

if

Параметры:

  • Guest - объект который установил состояние
  • curScr - если текущий экран
  • prScr - если предидущий экран
  • wasScr - если был экран
  • obj - объект
  • st - объект находится в состоянии
  • par - параметр объекта
  • op - операция сравнения с заданным значением. Может быть:
    • < - меньше
    • > - больше
    •  != - не равно
    • <> - не равно
    • >= - больше или равно
    • <= - меньше или равно
  • val - значение
  • buy - совершена ли покупка


Если использовать obj-par-val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.

Если использовать obj-par-op-val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записаного в поле val.

По отдельноси каждый из if-ов возвращает значение true или false, далее с if-ами можно создавать логические выражения, в том числе со знаками приоритета(скобочками), например в set-aх.

Логические операции:

  • , - и
  • & - и
  • | - или
  •  ! - не

Пример записи логического выражения в поле if set-a: (1&2)|(3&(!4))

play

play - проиграть звук

  • snd - Короткий звук (перетаскивается из редактора ресурсов)
  • voice - Голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов)
  • mus - Длинный звук (перетаскивается из редактора ресурсов)
  • preload - Указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом
  • loop - Зациклить звук (звуки)
  • mus_stop - Остановить текущую музыку
  • volume - Установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии
  • if - Номер (начиная с нуля) условия перехода (команды if)

var

Переменная, которой присваивается значение параметра объекта

  • name - имя переменной
  • obj - объект, используемый далее
  • par - Имя параметра, значение которого присваивается переменной
  • val - Значение переменной, если отсутствуют obj и par

Основы работы машины состояний

Рассмотрим пример простой машины состояний. Пусть объект (лампочка) находится в состоянии "off". При клике на него мышкой, он переходит в состояние "on", в котором находится 3000 ms, через которые возвращается в состояние "off". В каждом состоянии рисуется своя картинка.

Для создания такой машины, в редакторе, в панеле свойств необходимо выбрать тип объекта "machine", после чего нажать на многоточие в последнем свойстве "states". Появится окно редактирования свойств машины:

On off prop.png

Нажав дважды кнопку "Добавить состояние", мы получим два списка со свойствами этих состояний. Зададим им имена, редактируя первое поля "имя". Далее, на имени первого состояния нажимаем правую кнопку мыши, и из списка команд выбираем первую - "draw". Она появится в списке свойств данного состояния. Кликнув на многоточие в поле ввода "draw", получим ещё одно окно со списком возможных параметров этой команды. Помечая галочкой параметр "res", и нажимая кнопку "Ok", мы увидим его в окне свойств состояния. Действуя аналогичным образом, формируем окно описания состояний в следующем виде:

On off.png

То, что у нас получилось, можно изобразить в виде следующего графа машины состояний:

On off st.png

Кружки обозначают состояния (у нас их два). Стрелки - переходы между состояниями. Нижняя стрелка - это переход в результате внешнего воздействия (клика мышкой на машину). В окне редактирования состояний это воздействие описывается командой click с единственным параметром go, обозначающим в какое состояние необходимо перейти. Верхняя стрелка - переход в результате процессов внутри состояния on. В данном случае, процесс один - wait. Начав работать, эта команда ждет время t=3000 миллисекунд (3 секунды), а затем выполняет обратный переход в соответствии с параметром go="off".

В каждом состоянии рисуются различные картинки для отображения машины. Этим заведуют команды draw, в единственный параметр которых res, перетаскивается соответствующая картинка из редактора ресурсов.

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

В дальнейшем, чтобы не приводить скриншоты редактора состояний, мы будем описывать их при помощи списка команд и их параметров. Так, машина, созданная выше, будет иметь следующее описание:


<st id="off">                      // состояние выключенной лампочки
    <draw res="lamp_off"/>         // рисовать картинку выключенной лампы
    <click go="on"/>               // при клике - идем в состояние "on"
</st>

<st id="on">                       // состояние включенной лампочки
    <draw res="lamp_on"/>          // рисовать картинку включенной лампы
    <wait t="3000" go="off"/>      // через 3 секунды возвращаемся в "off"
</st>

Cкобки < . . . /> ограничивают список параметров команды. Состояние, начинается с записи <st id="имя состояния"> и заканчивается записью </st>, в себе содержит все команды этого состояния. После двух слешей идет пояснение (комментарий).

Общие принципы

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

Def states.png

Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.

Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы. Таким образом, все команды, которые мы задаем, при описании данного состояния, разбиваются на три группы:

  • Инициализации:
    • draw - установка графического ресурса
    • init - инициализация параметров машины (координаты и т.п.)
    • set - установка состояния другого объекта
  • Процессов:
    • wait - задержка по времени
    • move - движение
    • alpha - изменение прозрачности
    • scale - изменение размера
    • rot - вращение вокруг точки пивота
    • phys - движение в силовом поле.
  • Воздействия:
    • click - что делать при клике на машине
    • drop - на машине отпущена клавиша мыши
    • drag - машину схватили и тащат
    • throw - машину схватили и кинули
    • apply - сработает при пересечении машины с линией или объектом

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

Взаимодействия машин

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

Lamp switcher.png

Лампочка может находится в двух состояниях: не светится ("dark") и светится ("light"). Аналогично, выключатель имеет два состояния включен ("on") и выключен ("off"). Пусть лампочка, как и раннее горит 3 секунды и тухнет. Однако загореться она может только, если выключатель включен. Кроме этого, выключатель, переходя в состояние "on", зажигает лампочку. Граф взаимодействующих машин выглядит следующим образом:

Lamp switcher st.png

Опишем состояния выключателя:


<st id="on">                          // выключатель включен
    <draw res="sw_on"/>               // картинка включенного выключателя
    <set obj="лампа" st="light"/>     // установить объект лампочка в состояние light
    <click go="off"/>                 // при клике - идем в состояние "off"
</st>

<st id="off">                         // выключатель выключен
    <draw res="sw_off"/>              // картинка выключенного выключателя
    <click go="on"/>                  // при клике - идем в состояние "on"
</st>

Как и раньше, в каждом состоянии определяются команды инициализации рисования (draw). Кроме этого, при входе в состояние "on", запускается команда set, которая переводит другую машину (лампочку) в некоторое состояние (зажигает её). Наконец, команда click переключает выключатель из одного состояния в другое.

Рассмотрим теперь состояния лампочки:


<st id="dark">                       // лампочка не светится
    <draw res="lamp_off"/>           // картинка выключенного выключателя
    <click go="light" if="0"/>       // при клике - идем в состояние "on"
    <if obj="выключатель" st="on"/>  // условие: находится ли объект obj в состоянии st
</st>

<st id="light">                      // лампочка светится
    <draw res="lamp_on"/>            // рисовать граф.ресурс (картинку) включенного выключателя
    <wait t="3000" go="dark"/>       // при клике - идем в состояние "on"
</st>

Команда лампочки click дополнена параметром if=0. В этом параметре указывается номер, начиная с нуля, команды if (таких команд может быть много). В команде if происходит проверка, находится ли выключатель в состоянии "on". Только если это условие выполняется, происходит переход по go. Если же выключатель выключен, клик на лампочке не приведёт к смене состояния.

Последовательность команд

Процессы внутри состояния могут менять положение машины на сцене (move), поворачивать её (rot), менять прозрачность (alpha) и т.д. Команд данного типа в состоянии может быть несколько. Например, движение вниз на 100 пикселей и вправо на 200 можно реализовать при помощи двух состояний:


<st id="down">                            // движемся вниз
    <move dy="100" t="1000" go="right"/>  // перемещаемся по y вниз за время t, затем go
</st>

<st id="right">                           // движемся вправо
    <move dx="200" t="2000"/>             // перемещаемся по x за время t и останавливаемся
</st>

В команде move задается величина перемещения и его длительность в миллисекундах. Если в этой команде есть параметр go, то по окончанию движения происходит переход в другое состояние.

Такое же движение можно реализовать при помощи только одного состояния, объединив две команды движения:


<st id="move">                      // комбинированное движение
    <move dy="100" t="1000"/>       // перемещаемся по y вниз за время t
    <move dx="200" t="2000"/>       // затем движемся по x за время t и останавливаемся
</st>

Подобные команды выполняются последовательно. При входе в состояние, начинает выполняться первая команда move. Когда она отработает, передаётся управление второй команде move и т.д. Когда все команды отработают, процесс движения прекращается. Если в последней команде есть параметр перехода go, то происходит соответствующий переход. Если его нет - машина остается жить в этом состоянии. Команд процессов разного типа в состоянии может быть несколько. В этом случае выполняется следующее правило:

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

Другими словами, если в состоянии есть последовательность команд:

   move rot alpha move alpha move

то, независимо от их чередования, они выстраиваются в параллельные списки процессов:

   move  rot    alpha
   move         alpha
   move

Эти списки начинают одновременно выполняться сверху вниз (отрабатывают команды move, одновременно с ними rot и alpha).

Def procesess.png

Например, если при описанном выше движении, объект должен одновременно вращаться на угол da за время t, то необходимо добавить команду вращения:


<st id="move">                 // комбинированное движение и вращение
    <move dy="100" t="1000"/>  // перемещаемся по y вниз за время t
    <move dx="200" t="2000"/>  // затем движемся по x за время t и останавливаемся
    <rot da="360" t="3000"/>   // поворачивается на 360 градусов за 3 секунды
</st>

В данном случае, объект начнет движение и одновременно будет поворачиваться. После окончания движения объект совершит полный оборот вокруг своей точки пивота. Если бы длительность t команды rot была больше 3000 ms, то объект, переместившись вниз и вправо, остановился, но продолжил свое вращение, пока не повернулся бы на 360 градусов.

Циклы и прерывания

Предположим нам необходимо, чтобы объект 3 раза совершил движение по сторонам квадрата и остановился. Последовательностью состояний этого добится нельзя, так как состояние не помнит своей истории (сколько раз мы в нем были). Поэтому организуем комбинированное движение:


<st id="move_square">                    // движение по сторонам квадрата
    <move dy="100" t="1000"/>            // вниз
    <move dx="100" t="1000"/>            // вправо
    <move dy="-100" t="1000"/>           // вверх
    <move dx="-100" t="1000" loop="2"/>  // влево
</st>

Параметр loop в последней команде move сообщает процессу, что ему нужно повториться ещё 2 раза с самого начала (с первой команды move). Таким образом, войдя в состояние и пройдя все команды move, машина один раз пройдет по сторонам квадрата. Затем, благодаря параметру loop, сделает это ещё 2 раза. Если loop=-1, то движение будет бесконечным. В примере выше, этого же можно было добиться, поставив в последней команде move, вместо loop=-1 параметр go="move_square" (перезапустить состояние). Кроме команды зацикливания данного процесса, можно из одних команд запускать другие (начинать процессы другого типа). Например, пусть объект движется вправо 1000 ms и вращается 2000 ms. Закончив полный оборот (на уже остановившемся объекте), он начинает снова двигаться вправо. Реализуется это так:


<st id="move_rot">                               // движение и вращение
    <move dx="100" t="1000"/>                    // сдвигаемся
    <rot da="360" t="2000" loop="-1" move="0"/>  // вращаемся
</st>

Команда вращения rot бесконечно зациклена (loop=-1). Кроме этого, параметр команды вращения move=0 запускает процессы движения сначала (с нулевой команды move). Напоминаем, что нумерация команд начинается с 0. Подобные параметры перезапуска процесса с некоторой команды можно вызывать из любой команды. Имена этих параметров совпадают с именами команд-процессов. Еще один параметр, управляющий ходом выполнения команд процесса - это break. Если этот параметр встречается в команде, то по её завершению, процесс останавливается и не передает дальнейшего управления следующим командам этого типа. При помощи прерывания можно выполнять различные процессы последовательно. Например, пусть мы хотим, чтобы объект переместился вправо и остановился. Затем повернулся, переместился влево и снова повернулся и т.д. Это можно реализовать следующим образом:


<st id="move_rot">                                 // туда-сюда
    <rot break="1"/>                               // 0: не вращаемся (da и t не заданы)
    <move dx="100" t="1000" break="1" rot="1"/>    // 0: сдвигаемся и останавливаемся
    <rot da="360" t="2000" break="1" move="1"/>    // 1: вращаемся
    <move dx="-100" t="1000" rot="2"/>             // 1: сдвигаемся и останавливаемся
    <rot da="360" t="2000" move="0"/>              // 2: вращаемся
</st>

Для наглядности, команды записаны в чередующемся порядке (так как они будут выполняться). Первая команда rot, с единственным параметром break, сразу приводит к прерыванию команд вращения. В последних командах rot и move параметр break можно не ставить, так как по окончанию процесса данного типа он прерывается по умолчанию (если нет loop или go). В списке свойств состояния команда break является чекбоксом, который, по умолчанию, помечен. Если он не помечен (или команды break нет), прерывания не происходит (пока вместо чекбокса нужно поставить 1).

Составные объекты

Для задания сложной анимации имеет смысл создавать машины, которые состоят из других машин. Рассмотрим карету, состоящую из двух колес и выхлопных флаеров (шлейф дыма) за каретой. При её движении колеса должны крутиться. Создадим в редакторе объект kareta, у которого есть три подобъекта (левый рисунок ниже):

Kareta w v.png

Чтобы колеса крутились синхронно с движением кареты, необходимо согласовать их угловую скорость w со скоростью v кареты. Выше приведена формула связывающая w, v и радиус колеса r. Эта формула учитывает, что угловая скорость задается как изменение угла в градусах за секунду (коэффициент в знаменателе переводит её в радианы). Сделаем каждое колесо следующей машиной состояний:


<st id="stop"/>      // в этом состоянии ни чего не происходит
<st id="rot">
    <rot v="187"/>   // колесо крутится с угловой скоростью v
</st>

Так как картинка колеса задана в общих свойствах объекта, в состояниях её переопределять не надо. Для кареты построим следующую машину:


<st id="stop">
    <set obj="koleso1" st="stop"/>   // останавливаем колеса
    <set obj="koleso2" st="stop"/>
    <set obj="flyer_fire" st="end"/> // выключаем дым
    <click go="run"/>                // при клике карета начинает ехать
</st>

<st id="run">
    <set obj="koleso1" st="rot"/>    // запускаем вращение колес
    <set obj="koleso2" st="rot"/>
    <set obj="flyer_fire" st="beg"/> // включаем дым
    <move tx="450" v="70"/>          // едем вправо за экран
    <move tx="-350" t="0"/>          // заехав, быстро перепрыгиваем за экран влево
    <move tx="0" v="70" go="stop"/>  // выезжаем в центр экрана и останавливаемся
</st>

Радиус колеса равен r=w/2 = 43/2. Поэтому, если карета движется со скоростью v=70 пикселей в сек, угловая скорость колес должна быть равна

   w=v*57.3/r = 70 * 57.3 / (43/2) = 187,

что учтено при задании параметп vr в состоянии "rot" колес.


Инициализация на выходе

Все команды инициализации выполняются на входе в состояние. Иногда необходимо их выполнить на выходе (когда машина покидает состояние). Для этого используется параметр break и параметры запуска других состояний. Например, пусть нам необходимо изменить состояние объекта lamp, при клике на некоторую машину. Это можно сделать, либо в команде set того состояния, куда перейдет машина, либо следующим образом (само состояние опускаем):


<set break="1"/>                   // 0: пустая, прерванная команда
<set obj="lamp" st="on"/>          // 1: эта запустится только из wait
<wait t="2000" go="next" set="1"/> // после ожидания переходим и меняем состояние лампы

Аналогично это можно делать из команд процессов. Например, пусть необходимо при заходе в состояние установить объект "A" в состояние "show", затем переместиться на dx, и после этого перемещения задать состояние объекта "B" в "play". Делаем это так:


<set obj="A" st="show" break="1"/>   // 0: объект "A" в состояние "show", затем
<move dx="100" t="1000" set="1"/>    // перемещаемся и затем следующий set
<set obj="B" st="play"/>             // 1: объект "B" в состояние "play"