Machine

Материал из wiki.appsalutecreator.com
Версия от 13:13, 18 сентября 2012; Avereskun (обсуждение | вклад) (Воздействия)
Перейти к: навигация, поиск

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

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


Введение

Рассмотрим пример простой машины состояний. Пусть объект (лампочка) находится в состоянии "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 = "off"                           // состояние выключенной лампочки
{
   draw  { res="lamp_off"        }   // рисовать картинку выключенной лампы
   click { go="on"               }   // при клике - идем в состояние "on"
}

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

Фигурные скобки { ... } после имени команд ограничивают список параметров команды. Состояние, начинающееся с записи st="имя состояния", ограничивает фигурными скобками все команды этого состояния. После двух слешей идет пояснение (комментарий).

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

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

Def states.png

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

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

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

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

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

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

Lamp switcher.png

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

Lamp switcher st.png

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

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

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

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

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

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

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

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

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

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

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

st = "left"                          // движемся вправо
{
   move { dx=200 t=2000 }            // перемещаемся по x за время t и останавливаемся
}

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

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

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

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

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

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

   move rot alpha move alpha move

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

   move  rot    alpha
   move         alpha
  move

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

Def procesess.png

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

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

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

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

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

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

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

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

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

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

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

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

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

Kareta w v.png

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

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

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

st="stop"
{
   set   { obj="koleso1"     st="stop"} // останавливаем колеса
   set   { obj="koleso2"     st="stop"}
   set   { obj="flyer_fire"  st="end" } // выключаем дым

   click { go="run" }                   // при клике карета начинает ехать
}

st="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"   } // выезжаем в центр экрана и останавливаемся
}

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

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

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

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

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

draw

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

  • res - ресурс картинки (перетаскивается из редактора ресурсов)
  • ft - длительность кадра в миллисекундах
  • c1 - номер первого кадра (начиная с нуля)
  • c2 - номер последнего кадра
  • c - номер стартового кадра
  • label - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз

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

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

init

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

  • x,y - координата точки пивота относительно сцены или родительского объекта;
  • w,h - ширина и высота машины (для области клика и т.п.);
  • px,py - координаты точки пивота относительно левого верхнего угла машины;
  • sx,sy - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);
  • ang - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;
  • v - скорость для команды move
  • vr - угловая скорость для команды rot
  • vx,vy - начальная скорость для команды phys
  • ax,ay - ускорение для команды phys

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

set

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

  • obj - изменяемый объект (выбирается из списка объектов);
  • st - состояние в которое переводится объект.

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

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

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

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

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

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

Процессы

wait

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

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

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

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

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

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

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

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

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

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

wait { go="next" t=1000 dt=200 }

move

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

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

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

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

rot

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

  • ta - целевой угол поворота объекта
  • da - на сколько надо повернуться (ta игнорируется)
  • vr - угловая скорость поворота в градусах в секунду
  • t - время поворота (vr игнорируется)

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

alpha

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

  • ta - целевая прозрачность
  • da - на сколько надо изменить прозрачность от текущей (ta игнорируется)
  • va - скорость изменения прозрачности (в долях единицы в ms)
  • dt - время изменения (v игнорируется)

scale

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

  • tx, ty - целевой масштаб по каждой оси
  • dx, dy - на сколько изменить масштаб по каждой оси
  • vs - скорость изменения масштаба (в долях единицы в сек.)
  • t - длительность выполнения команды (v игнорируется)

phys

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

  • vx, vy - начальная скорость
  • ax, ay - величина ускорения по каждой оси
  • tvx, tvy - целевая скорость
  • tx, ty - целевая координата

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

st = "down"                                        // падаем
{
   phys { vy=0 ay=20 ty=0 go="touch" }
}

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

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

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

Воздействия

click

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

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

touch_in

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

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

touch_out

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

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

drag

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

  • x1 - разрешено таскать, когда координата объекта правее;
  • x2 - разрешено таскать, когда координата объекта левее;
  • y1 - разрешено таскать, когда координата объекта ниже;
  • y2 - разрешено таскать, когда координата объекта выше;
  • if - номер команды условия разрешения таскания.

drop

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

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

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

st="drag"
{
   drag{ y1=-250 x1=-350 y2=250 x2=350}// ограничиваем прямоугольник, где можно таскать
   drop{ obj="box"  go="open"         }// при бросании на ящик, переходим в open
}

st="open"
{
   set   { obj="box" st="open" }               // открываем ящик (переводя его в "open")
   scale { tx="0.01" ty="0.01" t=500 go="hide"}// уменьшаем ключ до 0 за 500 ms
}

st="hide"
{
   init  { x=268  y=30                }// возвращаем колюч на исходную позицию
   scale { tx=1  ty=1  t=500 go="drag"}// увеличиваем его размеры и даем готовность таскать
}

Ящик:

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

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

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="throw"
{
   init  { x=-350 y=150 }                 // начальное положение
   throw { go="fly"     }                 // бросаем
}

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

over

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