https://wiki.appsalutecreator.com/api.php?action=feedcontributions&user=Atonkonog&feedformat=atomwiki.appsalutecreator.com - Вклад участника [ru]2024-03-29T10:30:43ZВклад участникаMediaWiki 1.31.15https://wiki.appsalutecreator.com/index.php?title=Machine&diff=5337Machine2014-01-30T13:56:13Z<p>Atonkonog: /* Random-псевдо */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки;<br />
** '''[[#download|download]]''' - запуск процедуры закачки контента.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#touch_up|touch_up]]''' - отжатие мыши от машины;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
Если на девайсе была нажата кнопка "отрейтинговать", то в опции запишется параметр rating значение 1, если нажата кнопка "позже" - rating 2, "никогда" - rating 3<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
*'''func''' - в выпадающем списке можно выбрать функцию:<br />
**'''random''' - использует arg1 и arg2, возвращает случайное целое число в диапазоне arg1 .. arg2.<br />
**'''conc''' - объединяет 4 строки arg1,arg2,arg3,arg4. Возвращает строку, в которой соединены все строки<br />
**'''exp''' - экспонента от аргумента arg1.<br />
**'''ln''' - натуральный логарифм аргумента arg1.<br />
*'''arg1''' - аргумент функции<br />
*'''arg2''' - аргумент функции<br />
*'''arg3''' - аргумент функции<br />
*'''arg4''' - аргумент функции<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
=== download ===<br />
<br />
<br />
При переходе в состояние будет совершена попытку закачать контент.<br />
* '''url''' - ссылка на zip архив с контентом в интернете.<br />
* '''объект успех''' - объект, которому в случае успешной закачки будет задаваться указанное состояние.<br />
* '''состояние (успех)''' - состояние, которое будет устанавливаться выше указанному объекту, в случае успешной закачки.<br />
* '''объект (провал)''' -объект, которому, в случае неудачи закачки, будет устанавливаться указанное состояние.<br />
* '''состояние (провал)''' - состояние, которое, в случае неудачи закачки,будет устанавливаться выше указанному объекту.<br />
* '''счетчик прогресса''' - объект, типа счетчик, который отображает прогресс закачки контента. Крайне желательно, что бы он измерялся в диапазоне от 0 до 100.<br />
<br />
Существует несколько причин при которых вызывается состояние "провал". Для того что бы сообщить пользователю, по какой именно причине возник провал закачки, следует идентифицировать причины провала. Это возможно сделать с помощью параметра <br />
<pre><br />
downloadErrCode<br />
</pre><br />
Ниже приведены значение параметра которые помогут вывести нужное текстовое сообщение :<br />
<pre><br />
GCUSTOM_ERROR_CODE_ERROR_UNKNOWN = 1, //!< ошибка неклассифицирована<br />
GCUSTOM_ERROR_CODE_WIFI_DISABLED = 2, //!< отключен WIFI<br />
GCUSTOM_ERROR_CODE_SDCARD_UNAVAILABLE = 3, //!< SD-карта недоступна<br />
GCUSTOM_ERROR_CODE_SDCARD_FULL = 4, //!< SD-карта переполнена перед закачкой<br />
GCUSTOM_ERROR_CODE_UNZIP_FAIL = 5 //!< ошибка при распаковки пака (скорее всего на SD-карте не хватает места для распаковки <br />
</pre><br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - прервать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
По клику машина записывает координаты клика в параметры: clickX, clickY.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== touch_up ===<br />
<br />
Отжатие мыши от машины<br />
<br />
* '''go''' - состояние в которое при отжатии мыши нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== drag ===<br />
<br />
Данная команда позволяет "таскать" объект по сцене нажав и удерживая клавишу мишки или (палец в случае сенсорного устройства) на нем.Так же есть возможность ограничить разрешенную область таскания, за пределы которой объект вытащить невозможно. [[Файл:drag.jpg|right]]<br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''за пивот''' - "да" - таскать объект за пивот, "нет" - за ту точку, за которую схватили<br />
<br />
=== dragRot ===<br />
<br />
Данная команда позволяет вращать объект вокруг точки пивота. Нажав и удерживая клавишу мишки или палец (в случае сенсорного устройства) на нем, мы можем вращать его по часовой либо против часовой стрелки. При многократном вращении вокруг своей оси значение его угла не накапливается, а обнуляется выходя за границы [360 ; -360] градусов. [[Файл:dragRot.jpg|right]]<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drag<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
[[Файл:Апплай.png|500px]]<br />
<br />
Блок схема работы '''apply'''<br />
<br />
[[Файл:Блок схема apply.png|500px]]<br />
<br />
* Сначала у нас проверяется координаты '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Далее проверяет если '''obj'''<br />
* Если '''obj''' нет, то идёт проверку, и выдаёт результат<br />
(если при этом если '''x1''', '''x2''', '''y1''', '''y2''' нет, то они считаются по ширине и высоте всего экрана.)<br />
* Если есть '''obj''', то проверяет есть ли радиусы '''rm''', '''ro'''.<br />
* Если он есть, то значит у нас '''apply''' по кругам<br />
* Если нет, то проверяем наличие '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Если они есть, то проверка и результат.<br />
* Если их нет, то проверка идёт по шейпам объектов, и выдаётся результат/<br />
Если не будет стоять ни каких галочек, то проверка будет идти по шейпам объектов.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
Для проверки текущего значения прозрачности у объекта можно воспользоваться параметром ''cur_al''<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Свойства объекта массив: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
=== Состояния объекта массив: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]<br />
<br />
<br />
==Пример использования==<br />
<br />
[http://fs5.absolutist.com/files/wikisample/machine.rar Download]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=5336Machine2014-01-30T13:56:00Z<p>Atonkonog: /* Random 2 */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки;<br />
** '''[[#download|download]]''' - запуск процедуры закачки контента.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#touch_up|touch_up]]''' - отжатие мыши от машины;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
Если на девайсе была нажата кнопка "отрейтинговать", то в опции запишется параметр rating значение 1, если нажата кнопка "позже" - rating 2, "никогда" - rating 3<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
*'''func''' - в выпадающем списке можно выбрать функцию:<br />
**'''random''' - использует arg1 и arg2, возвращает случайное целое число в диапазоне arg1 .. arg2.<br />
**'''conc''' - объединяет 4 строки arg1,arg2,arg3,arg4. Возвращает строку, в которой соединены все строки<br />
**'''exp''' - экспонента от аргумента arg1.<br />
**'''ln''' - натуральный логарифм аргумента arg1.<br />
*'''arg1''' - аргумент функции<br />
*'''arg2''' - аргумент функции<br />
*'''arg3''' - аргумент функции<br />
*'''arg4''' - аргумент функции<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
=== download ===<br />
<br />
<br />
При переходе в состояние будет совершена попытку закачать контент.<br />
* '''url''' - ссылка на zip архив с контентом в интернете.<br />
* '''объект успех''' - объект, которому в случае успешной закачки будет задаваться указанное состояние.<br />
* '''состояние (успех)''' - состояние, которое будет устанавливаться выше указанному объекту, в случае успешной закачки.<br />
* '''объект (провал)''' -объект, которому, в случае неудачи закачки, будет устанавливаться указанное состояние.<br />
* '''состояние (провал)''' - состояние, которое, в случае неудачи закачки,будет устанавливаться выше указанному объекту.<br />
* '''счетчик прогресса''' - объект, типа счетчик, который отображает прогресс закачки контента. Крайне желательно, что бы он измерялся в диапазоне от 0 до 100.<br />
<br />
Существует несколько причин при которых вызывается состояние "провал". Для того что бы сообщить пользователю, по какой именно причине возник провал закачки, следует идентифицировать причины провала. Это возможно сделать с помощью параметра <br />
<pre><br />
downloadErrCode<br />
</pre><br />
Ниже приведены значение параметра которые помогут вывести нужное текстовое сообщение :<br />
<pre><br />
GCUSTOM_ERROR_CODE_ERROR_UNKNOWN = 1, //!< ошибка неклассифицирована<br />
GCUSTOM_ERROR_CODE_WIFI_DISABLED = 2, //!< отключен WIFI<br />
GCUSTOM_ERROR_CODE_SDCARD_UNAVAILABLE = 3, //!< SD-карта недоступна<br />
GCUSTOM_ERROR_CODE_SDCARD_FULL = 4, //!< SD-карта переполнена перед закачкой<br />
GCUSTOM_ERROR_CODE_UNZIP_FAIL = 5 //!< ошибка при распаковки пака (скорее всего на SD-карте не хватает места для распаковки <br />
</pre><br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - прервать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
По клику машина записывает координаты клика в параметры: clickX, clickY.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== touch_up ===<br />
<br />
Отжатие мыши от машины<br />
<br />
* '''go''' - состояние в которое при отжатии мыши нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== drag ===<br />
<br />
Данная команда позволяет "таскать" объект по сцене нажав и удерживая клавишу мишки или (палец в случае сенсорного устройства) на нем.Так же есть возможность ограничить разрешенную область таскания, за пределы которой объект вытащить невозможно. [[Файл:drag.jpg|right]]<br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''за пивот''' - "да" - таскать объект за пивот, "нет" - за ту точку, за которую схватили<br />
<br />
=== dragRot ===<br />
<br />
Данная команда позволяет вращать объект вокруг точки пивота. Нажав и удерживая клавишу мишки или палец (в случае сенсорного устройства) на нем, мы можем вращать его по часовой либо против часовой стрелки. При многократном вращении вокруг своей оси значение его угла не накапливается, а обнуляется выходя за границы [360 ; -360] градусов. [[Файл:dragRot.jpg|right]]<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drag<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
[[Файл:Апплай.png|500px]]<br />
<br />
Блок схема работы '''apply'''<br />
<br />
[[Файл:Блок схема apply.png|500px]]<br />
<br />
* Сначала у нас проверяется координаты '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Далее проверяет если '''obj'''<br />
* Если '''obj''' нет, то идёт проверку, и выдаёт результат<br />
(если при этом если '''x1''', '''x2''', '''y1''', '''y2''' нет, то они считаются по ширине и высоте всего экрана.)<br />
* Если есть '''obj''', то проверяет есть ли радиусы '''rm''', '''ro'''.<br />
* Если он есть, то значит у нас '''apply''' по кругам<br />
* Если нет, то проверяем наличие '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Если они есть, то проверка и результат.<br />
* Если их нет, то проверка идёт по шейпам объектов, и выдаётся результат/<br />
Если не будет стоять ни каких галочек, то проверка будет идти по шейпам объектов.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
Для проверки текущего значения прозрачности у объекта можно воспользоваться параметром ''cur_al''<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Свойства объекта массив: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
=== Состояния объекта массив: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]<br />
<br />
<br />
==Пример использования==<br />
<br />
[http://fs5.absolutist.com/files/wikisample/machine.rar Download]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=5335Machine2014-01-30T13:55:46Z<p>Atonkonog: /* Random */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки;<br />
** '''[[#download|download]]''' - запуск процедуры закачки контента.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#touch_up|touch_up]]''' - отжатие мыши от машины;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
Если на девайсе была нажата кнопка "отрейтинговать", то в опции запишется параметр rating значение 1, если нажата кнопка "позже" - rating 2, "никогда" - rating 3<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
*'''func''' - в выпадающем списке можно выбрать функцию:<br />
**'''random''' - использует arg1 и arg2, возвращает случайное целое число в диапазоне arg1 .. arg2.<br />
**'''conc''' - объединяет 4 строки arg1,arg2,arg3,arg4. Возвращает строку, в которой соединены все строки<br />
**'''exp''' - экспонента от аргумента arg1.<br />
**'''ln''' - натуральный логарифм аргумента arg1.<br />
*'''arg1''' - аргумент функции<br />
*'''arg2''' - аргумент функции<br />
*'''arg3''' - аргумент функции<br />
*'''arg4''' - аргумент функции<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
=== download ===<br />
<br />
<br />
При переходе в состояние будет совершена попытку закачать контент.<br />
* '''url''' - ссылка на zip архив с контентом в интернете.<br />
* '''объект успех''' - объект, которому в случае успешной закачки будет задаваться указанное состояние.<br />
* '''состояние (успех)''' - состояние, которое будет устанавливаться выше указанному объекту, в случае успешной закачки.<br />
* '''объект (провал)''' -объект, которому, в случае неудачи закачки, будет устанавливаться указанное состояние.<br />
* '''состояние (провал)''' - состояние, которое, в случае неудачи закачки,будет устанавливаться выше указанному объекту.<br />
* '''счетчик прогресса''' - объект, типа счетчик, который отображает прогресс закачки контента. Крайне желательно, что бы он измерялся в диапазоне от 0 до 100.<br />
<br />
Существует несколько причин при которых вызывается состояние "провал". Для того что бы сообщить пользователю, по какой именно причине возник провал закачки, следует идентифицировать причины провала. Это возможно сделать с помощью параметра <br />
<pre><br />
downloadErrCode<br />
</pre><br />
Ниже приведены значение параметра которые помогут вывести нужное текстовое сообщение :<br />
<pre><br />
GCUSTOM_ERROR_CODE_ERROR_UNKNOWN = 1, //!< ошибка неклассифицирована<br />
GCUSTOM_ERROR_CODE_WIFI_DISABLED = 2, //!< отключен WIFI<br />
GCUSTOM_ERROR_CODE_SDCARD_UNAVAILABLE = 3, //!< SD-карта недоступна<br />
GCUSTOM_ERROR_CODE_SDCARD_FULL = 4, //!< SD-карта переполнена перед закачкой<br />
GCUSTOM_ERROR_CODE_UNZIP_FAIL = 5 //!< ошибка при распаковки пака (скорее всего на SD-карте не хватает места для распаковки <br />
</pre><br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - прервать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
По клику машина записывает координаты клика в параметры: clickX, clickY.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== touch_up ===<br />
<br />
Отжатие мыши от машины<br />
<br />
* '''go''' - состояние в которое при отжатии мыши нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== drag ===<br />
<br />
Данная команда позволяет "таскать" объект по сцене нажав и удерживая клавишу мишки или (палец в случае сенсорного устройства) на нем.Так же есть возможность ограничить разрешенную область таскания, за пределы которой объект вытащить невозможно. [[Файл:drag.jpg|right]]<br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''за пивот''' - "да" - таскать объект за пивот, "нет" - за ту точку, за которую схватили<br />
<br />
=== dragRot ===<br />
<br />
Данная команда позволяет вращать объект вокруг точки пивота. Нажав и удерживая клавишу мишки или палец (в случае сенсорного устройства) на нем, мы можем вращать его по часовой либо против часовой стрелки. При многократном вращении вокруг своей оси значение его угла не накапливается, а обнуляется выходя за границы [360 ; -360] градусов. [[Файл:dragRot.jpg|right]]<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drag<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
[[Файл:Апплай.png|500px]]<br />
<br />
Блок схема работы '''apply'''<br />
<br />
[[Файл:Блок схема apply.png|500px]]<br />
<br />
* Сначала у нас проверяется координаты '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Далее проверяет если '''obj'''<br />
* Если '''obj''' нет, то идёт проверку, и выдаёт результат<br />
(если при этом если '''x1''', '''x2''', '''y1''', '''y2''' нет, то они считаются по ширине и высоте всего экрана.)<br />
* Если есть '''obj''', то проверяет есть ли радиусы '''rm''', '''ro'''.<br />
* Если он есть, то значит у нас '''apply''' по кругам<br />
* Если нет, то проверяем наличие '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Если они есть, то проверка и результат.<br />
* Если их нет, то проверка идёт по шейпам объектов, и выдаётся результат/<br />
Если не будет стоять ни каких галочек, то проверка будет идти по шейпам объектов.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
Для проверки текущего значения прозрачности у объекта можно воспользоваться параметром ''cur_al''<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Свойства объекта массив: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
=== Состояния объекта массив: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]<br />
<br />
<br />
==Пример использования==<br />
<br />
[http://fs5.absolutist.com/files/wikisample/machine.rar Download]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=5331Machine2014-01-30T11:22:58Z<p>Atonkonog: </p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки;<br />
** '''[[#download|download]]''' - запуск процедуры закачки контента.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#touch_up|touch_up]]''' - отжатие мыши от машины;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
Если на девайсе была нажата кнопка "отрейтинговать", то в опции запишется параметр rating значение 1, если нажата кнопка "позже" - rating 2, "никогда" - rating 3<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
*'''func''' - в выпадающем списке можно выбрать функцию:<br />
**'''random''' - использует arg1 и arg2, возвращает случайное целое число в диапазоне arg1 .. arg2.<br />
**'''conc''' - объединяет 4 строки arg1,arg2,arg3,arg4. Возвращает строку, в которой соединены все строки<br />
**'''exp''' - экспонента от аргумента arg1.<br />
**'''ln''' - натуральный логарифм аргумента arg1.<br />
*'''arg1''' - аргумент функции<br />
*'''arg2''' - аргумент функции<br />
*'''arg3''' - аргумент функции<br />
*'''arg4''' - аргумент функции<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
=== download ===<br />
<br />
<br />
При переходе в состояние будет совершена попытку закачать контент.<br />
* '''url''' - ссылка на zip архив с контентом в интернете.<br />
* '''объект успех''' - объект, которому в случае успешной закачки будет задаваться указанное состояние.<br />
* '''состояние (успех)''' - состояние, которое будет устанавливаться выше указанному объекту, в случае успешной закачки.<br />
* '''объект (провал)''' -объект, которому, в случае неудачи закачки, будет устанавливаться указанное состояние.<br />
* '''состояние (провал)''' - состояние, которое, в случае неудачи закачки,будет устанавливаться выше указанному объекту.<br />
* '''счетчик прогресса''' - объект, типа счетчик, который отображает прогресс закачки контента. Крайне желательно, что бы он измерялся в диапазоне от 0 до 100.<br />
<br />
Существует несколько причин при которых вызывается состояние "провал". Для того что бы сообщить пользователю, по какой именно причине возник провал закачки, следует идентифицировать причины провала. Это возможно сделать с помощью параметра <br />
<pre><br />
downloadErrCode<br />
</pre><br />
Ниже приведены значение параметра которые помогут вывести нужное текстовое сообщение :<br />
<pre><br />
GCUSTOM_ERROR_CODE_ERROR_UNKNOWN = 1, //!< ошибка неклассифицирована<br />
GCUSTOM_ERROR_CODE_WIFI_DISABLED = 2, //!< отключен WIFI<br />
GCUSTOM_ERROR_CODE_SDCARD_UNAVAILABLE = 3, //!< SD-карта недоступна<br />
GCUSTOM_ERROR_CODE_SDCARD_FULL = 4, //!< SD-карта переполнена перед закачкой<br />
GCUSTOM_ERROR_CODE_UNZIP_FAIL = 5 //!< ошибка при распаковки пака (скорее всего на SD-карте не хватает места для распаковки <br />
</pre><br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - прервать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
По клику машина записывает координаты клика в параметры: clickX, clickY.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== touch_up ===<br />
<br />
Отжатие мыши от машины<br />
<br />
* '''go''' - состояние в которое при отжатии мыши нужно перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход ''go''.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды нужно перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход ''go''.<br />
<br />
=== drag ===<br />
<br />
Данная команда позволяет "таскать" объект по сцене нажав и удерживая клавишу мишки или (палец в случае сенсорного устройства) на нем.Так же есть возможность ограничить разрешенную область таскания, за пределы которой объект вытащить невозможно. [[Файл:drag.jpg|right]]<br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''за пивот''' - "да" - таскать объект за пивот, "нет" - за ту точку, за которую схватили<br />
<br />
=== dragRot ===<br />
<br />
Данная команда позволяет вращать объект вокруг точки пивота. Нажав и удерживая клавишу мишки или палец (в случае сенсорного устройства) на нем, мы можем вращать его по часовой либо против часовой стрелки. При многократном вращении вокруг своей оси значение его угла не накапливается, а обнуляется выходя за границы [360 ; -360] градусов. [[Файл:dragRot.jpg|right]]<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у которого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drag<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
[[Файл:Апплай.png|500px]]<br />
<br />
Блок схема работы '''apply'''<br />
<br />
[[Файл:Блок схема apply.png|500px]]<br />
<br />
* Сначала у нас проверяется координаты '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Далее проверяет если '''obj'''<br />
* Если '''obj''' нет, то идёт проверку, и выдаёт результат<br />
(если при этом если '''x1''', '''x2''', '''y1''', '''y2''' нет, то они считаются по ширине и высоте всего экрана.)<br />
* Если есть '''obj''', то проверяет есть ли радиусы '''rm''', '''ro'''.<br />
* Если он есть, то значит у нас '''apply''' по кругам<br />
* Если нет, то проверяем наличие '''x1''', '''x2''', '''y1''', '''y2'''.<br />
* Если они есть, то проверка и результат.<br />
* Если их нет, то проверка идёт по шейпам объектов, и выдаётся результат/<br />
Если не будет стоять ни каких галочек, то проверка будет идти по шейпам объектов.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
Для проверки текущего значения прозрачности у объекта можно воспользоваться параметром ''cur_al''<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Свойства объекта массив: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
=== Состояния объекта массив: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]<br />
<br />
<br />
==Пример использования==<br />
<br />
[http://fs5.absolutist.com/files/wikisample/machine.rar Download]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5128Проектирование экранов игры2013-09-10T07:03:21Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление озвучкой.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
[[Файл:scene_book_2.jpg]]<br />
<br />
==Принципы формирования экранов в хидденах==<br />
<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило отсылается количество предметов, найденных игроком и информация об использовании подсказок<br />
<br />
2. Игровая сцена - содержит поисковые объекты и подложки/накладки поисковых объектов, музыку и пр. уникальные элементы, характерные конкретно для этого уровня.<br />
<br />
3. Игровое меню - глобальная сцена, реализующая игровое меню с интерфейсными окнами<br />
<br />
4. Меню устройства - меню, которое реализует нажатие кнопок устройства.<br />
<br />
[[Файл:scene_hidden.jpg]]<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5127Проектирование экранов игры2013-09-10T06:56:59Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
[[Файл:scene_book_2.jpg]]<br />
<br />
==Принципы формирования экранов в хидденах==<br />
<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило отсылается количество предметов, найденных игроком и информация об использовании подсказок<br />
<br />
2. Игровая сцена - содержит поисковые объекты и подложки/накладки поисковых объектов, музыку и пр. уникальные элементы, характерные конкретно для этого уровня.<br />
<br />
3. Игровое меню - глобальная сцена, реализующая игровое меню с интерфейсными окнами<br />
<br />
4. Меню устройства - меню, которое реализует нажатие кнопок устройства.<br />
<br />
[[Файл:scene_hidden.jpg]]<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5126Проектирование экранов игры2013-09-09T15:45:32Z<p>Atonkonog: /* Принципы формирования экранов в хидденах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
[[Файл:scene_book_2.jpg]]<br />
<br />
==Принципы формирования экранов в хидденах==<br />
<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило отсылается количество предметов, найденных игроком и информация об использовании подсказок<br />
<br />
2. Игровая сцена - содержит поисковые объекты и подложки/накладки поисковых объектов, музыку и пр. уникальные элементы, характерные конкретно для этого уровня.<br />
<br />
3. Игровое меню - глобальная сцена, реализующая игровое меню с интерфейсными окнами<br />
<br />
4. Меню устройства - меню, которое реализует нажатие кнопок устройства.<br />
<br />
[[Файл:scene_hidden.jpg]]<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5125Проектирование экранов игры2013-09-09T15:45:01Z<p>Atonkonog: /* Принципы формирования экранов в хидденах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
[[Файл:scene_book_2.jpg]]<br />
<br />
==Принципы формирования экранов в хидденах==<br />
<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило отсылается количество предметов, найденных игроком и информация об использовании подсказок<br />
<br />
2. Игровая сцена - содержит поисковые объекты и подложки/накладки поисковых объектов, музыку и пр. уникальные элементы, характерные конкретно для этого уровня.<br />
<br />
3. Игровое меню - глобальная сцена, реализующая игровое меню с интерфейсными окнами<br />
<br />
4. Меню устройства - меню, которое реализует нажатие кнопок устройства.<br />
[[Файл:scene_hidden.jpg]]<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Scene_hidden.jpg&diff=5124Файл:Scene hidden.jpg2013-09-09T15:44:15Z<p>Atonkonog: </p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5123Проектирование экранов игры2013-09-09T15:43:34Z<p>Atonkonog: /* Принципы формирования экранов в квестах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
[[Файл:scene_book_2.jpg]]<br />
<br />
==Принципы формирования экранов в хидденах==<br />
[[Файл:scene_hidden.jpg|right]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило отсылается количество предметов, найденных игроком и информация об использовании подсказок<br />
<br />
2. Игровая сцена - содержит поисковые объекты и подложки/накладки поисковых объектов, музыку и пр. уникальные элементы, характерные конкретно для этого уровня.<br />
<br />
3. Игровое меню - глобальная сцена, реализующая игровое меню с интерфейсными окнами<br />
<br />
4. Меню устройства - меню, которое реализует нажатие кнопок устройства.<br />
<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Scene_book_2.jpg&diff=5120Файл:Scene book 2.jpg2013-09-06T13:12:06Z<p>Atonkonog: </p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5119Проектирование экранов игры2013-09-06T13:11:30Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
[[Файл:scene_book_2.jpg]]<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5118Проектирование экранов игры2013-09-06T12:37:10Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - обработка нажатия функциональных кнопок устройства (например, когда игрок закрывает приложение)<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5117Проектирование экранов игры2013-09-06T12:19:01Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книги, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - глобальная сцена с интерфейсными кнопками.<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5116Проектирование экранов игры2013-09-06T11:29:52Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
<br />
При создании книги, полезно использовать следующие сцены:<br />
[[Файл:scene_book.jpg|left]]<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книге, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - глобальная сцена с интерфейсными кнопками.<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5115Проектирование экранов игры2013-09-06T11:29:33Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
[[Файл:scene_book.jpg|left]]<br />
При создании книги, полезно использовать следующие сцены:<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книге, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - глобальная сцена с интерфейсными кнопками.<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5114Проектирование экранов игры2013-09-06T11:29:10Z<p>Atonkonog: /* Принципы формирования экранов в книгах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
[[Файл:scene_book.jpg]|left]<br />
При создании книги, полезно использовать следующие сцены:<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книге, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - глобальная сцена с интерфейсными кнопками.<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Scene_book.jpg&diff=5113Файл:Scene book.jpg2013-09-06T11:28:35Z<p>Atonkonog: </p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5112Проектирование экранов игры2013-09-06T10:24:13Z<p>Atonkonog: /* Принципы формирования экранов в квестах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в книгах==<br />
[[Файл:scene_book.jpg]]<br />
При создании книги, полезно использовать следующие сцены:<br />
1. Flurry - сцена, для отсылки действий пользователя на сервер. Нужна для сборки статистики. Как правило, отсылаются: экран, количество секунд, проведённых на нём, действия игрока на сцене. Как правило, сцена не делается расшаренной, однако при помощи групп можно сделать её расшаренной, с некоторыми локальными модификациями, при помощи групп.<br />
<br />
2. Интерактивная начинка книги. Уникальная сцена для каждой страницы книги. Содержит "игровые" элементы книги. Например, котик, мурчащий при клике на него, зайчик, убегающий при клике и т. п.<br />
<br />
3. Стрелки. Стрелки переключения на следующую/предыдущую страницу книги.<br />
<br />
4. Всплывающий список страниц - расшаренная сцена, всплывающая при клике на неё. Содержит уменьшенные картинки страниц книге, при клике на которые происходит переход на соответствующую страницу.<br />
<br />
5. Текст - текст книги и управление голосом.<br />
<br />
6. Уши. Части экрана, которые будут видны, если соотношение сторон на устройстве, отличается от оригинального соотношения сторон в книге. <br />
<br />
7. Меню - глобальная сцена с интерфейсными кнопками.<br />
<br />
<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Scene_quest.jpg&diff=5111Файл:Scene quest.jpg2013-09-05T11:12:16Z<p>Atonkonog: загружена новая версия «Файл:Scene quest.jpg»</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Scene_quest.jpg&diff=5110Файл:Scene quest.jpg2013-09-05T10:33:51Z<p>Atonkonog: </p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5109Проектирование экранов игры2013-09-05T10:33:18Z<p>Atonkonog: /* Принципы формирования экранов в квестах */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в квестах==<br />
[[Файл:scene_quest.jpg|right]]<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%BE%D0%B2_%D0%B8%D0%B3%D1%80%D1%8B&diff=5098Проектирование экранов игры2013-09-04T14:12:52Z<p>Atonkonog: /* Принципы формирования сцен и их наполнения */</p>
<hr />
<div>[[Файл:Layout.png|right]]<br />
Немного вводных терминов для начала проектирования экранов игры. <br />
<br />
Игра обычно запускается на различных устройствах (телефон, планшетник, десктоп), важным понятием является лейаут (layout). <br />
Условно ''layout'' - это различные мониторы, имеющие то или иное разрешение в пикселях и разное соотношение высоты и ширины. Игра может проектироваться только для одного лейаута, однако чаще поддерживается сразу несколько лейаутов. <br />
<br />
Игра состоит из набора экранов. На каждом экране может находится одна или более сцена. <br />
Например, пусть на экране находится игровое поле и панель с интерфейсными кнопками. Эти две области можно оформить при помощи различных сцен. Сцены содержат игровые объекты. Ими могут быть картинки, базовые элементы управления (кнопки, чекбоксы), миниигры, универсальные машины состояний (программирующие логику) и т.д. <br />
<br />
*'''Лейаут''' - Проект с заданными параметрами физического разрешения экрана <br />
*'''Экран''' - Основной объект используемый для проектирования уровней игр, должен содержать как минимум одну сцену.<br />
*'''Сцена''' - принадлежит экрану, содержит объекты игры. Размеры сцены могут отличаться от размеров лейаута.<br />
<br />
<br />
==Принципы формирования сцен и их наполнения==<br />
<br />
*Сцены следует формировать по группам. То есть в одну сцену необходимо выносить меню миниигры, в другую фон, в третью - группы объектов. <br />
*Также, в некоторых случаях, чаще всего в адвентюрах, в отдельные сцены одного экрана можно выносить несколько не нагруженных локаций для быстрого перехода между ними. В таком варианте одна сцена выключается, другая - включается. <br />
*В Хидденах в отдельную сцену можно выносить хидденобъекты и фон, т.к. при наличии "утки" фон тоже должен быть масштабирован. <br />
*В отдельую расшаренную сцену также целесообразно выносить объекты которые будут использоваться на нескольких экранах - инвентарь, навигационные кнопки и машины и другие объекты.<br />
<br />
==Принципы формирования экранов в квестах==<br />
<br />
При создании квеста, сцены располагаются, как правило, в следующем порядке:<br />
<br />
1. Главная сцена (Main) - сцена-менеджер. В этой сцене располагается 1 объект (main), который, в звисимости от того, на какую сцену переходит игрок включает/выключает сцены или объекты сцен. Эта сцена должна быть расположенной первой в списке сцен, дабы её объект обрабатывался раньше других. Если у вас громоздкая сцена, и вы не можете добавить на экран другие сцены, по причине переполнения памяти — необходимость в сцене-менеджере сцен отпадает.<br />
<br />
2. Игровые сцены — семейство сцен, каждая из которых представляет собой отдельный игровой экран. Несколько сцен объединяются в один экран для увеличения скорости работы проекта, т. к. одновременно может быть загружен только 1 экран, и при переходе между экранами, игра может слегка притормаживать. Игровая сцена практически всегда содержит фон. Также, если сцена сложная, разумно добавить менеджер сцены.<br />
<br />
3. Общие сцены — сцены, объекты которых нужны в нескольких сценах из п. 2. Например, у нас есть экран, содержащий 2 сцены: дверь персонажа и комната персонажа. В обоих случаях диалоги с персонажем используются, однако координаты рамок отличаются. Разумно логику диалогов и рамки диалогов вынести в отдельную сцену.<br />
<br />
4. Инвентарные объекты — все инвентарные объекты должны быть расположены в одной сцене. Это нужно для экономии памяти.<br />
<br />
5. Расшаренные сцены. По сути, на экране присутствует только ссылка на сцену. Т. е., сцена используется на многих экранах, при этом логика её описана в одном месте. Такие сцены используют для различных интерфейсных элементов: инвентарь, разнообразные панели, меню, хиддены и т. п. При этом, очень помогает в работе объект типа Group. В расшаренной сцене присутствует обращение к группе, а на самой сцене присутствует объект типа этой группы. Например, таким образом полезно обрабатывать кнопку подсказки. Сама кнопка переводит объект группы в новое состояние, а на сцене присутствует объект, принадлежащий к этой группе, и имеющий указанное состояние. Также, следует помнить о том, что одновременно видимым может быть только один объект принадлежащий к группе, иначе возникнет ошибка.<br />
<br />
===Об экономии памяти=== <br />
<br />
Следует отдельно отметить, что вся графика сцены упаковывается в отдельный текстурный атлас (или множество атласов). Поэтому, не следует злоупотреблять разделением на сцены.<br />
<br />
===Об инвентарных объектах===<br />
<br />
Не следует помещать инвентарные объекты на расшаренную сцену, без крайней необходимости. В противном случае, вы получите лишние 1-2 МБ памяти, занятых Вашим приложением. Вместо этого, поступают следующим образом:<br />
1. Создаёте сцену где объект берётся в инвентарь<br />
2. Временно расшариваете эту сцену на экране, где этот предмет применяется<br />
3. Прописываете все необходимые применения предмета<br />
4. Удаляете расшаренную сцену. При этом, связи предмета не пропадут.<br />
5. Если нужно сделать изменения в применении предмета, возвращаетесь к п. 2</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Text2.PNG&diff=5097Файл:Text2.PNG2013-08-30T15:12:53Z<p>Atonkonog: загружена новая версия «Файл:Text2.PNG»: сделан скриншот с новыми текстовыми полями</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Text11.png&diff=5096Файл:Text11.png2013-08-30T14:17:57Z<p>Atonkonog: загружена новая версия «Файл:Text11.png»: Возврат к версии от 12:55, 30 августа 2013</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Text11.png&diff=5095Файл:Text11.png2013-08-30T14:17:12Z<p>Atonkonog: загружена новая версия «Файл:Text11.png»: -</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Text&diff=5094Text2013-08-30T13:57:35Z<p>Atonkonog: /* Пример применения */</p>
<hr />
<div>== Введение ==<br />
[[Файл:2223.png]]<br><br />
Для отображения текстовой информации с поддержкой многоязычности. Для управления текстовыми ресурсами используется TextEditor. <br><br />
<br />
Если необходимо разместить текст на сцене необходимо создать объект с типом text и перетащить на поле текстID текстовую строку из TextEditor. Также можно просто перенести их TextEditor выбранную текстовую запись, при этом автоматически создастся объект с типом Text.<br><br />
<br />
<br />
== Параметры объекта ==<br />
<br />
=== Общие параметры ===<br />
(см. описание [[Object|Object]])<br />
<br />
=== Основные параметры ===<br />
<br />
*'''res''' - Графический ресурс подложки на которой выводится текст. Перетаскивается мышкой из редактора текста (поле должно находится в состоянии редактирования). Может отсутствовать.<br />
*'''текстID''' - Выводимый текст перетаскивается из ресурса тектстов, для перетягивания поле в объекте Text должно быть в режиме редактирования. Решетка (#) разделяет на страницы, черта (|) - принудительный переход на новую строку.<br />
*'''текст''' - Выводимый текст без использования базы текстовых ресурсов. Решетка (#) разделяет на страницы, черта (|) - принудительный переход на новую строку.<br />
*'''состояние''' - в поле указывается состояние текстового объекта, в которое он перейдет при загрузке экрана (это поле часто оставляют пустым, а состояния задают машиной). Состояния текстового объекта:<br />
<br />
- ''start'' - это состояние проверяет время ''до открытия'' и переходит либо в ''beg'', если время до открытия не ноль, либо в ''open'', если время до открытия равняется нулю;<br />
<br />
- ''beg'' - это состояние "ждет" время ''до открытия'' и переходит в ''open'';<br />
<br />
- ''open'' - плавно проявляет текст до его нормального ''alpha'' в течении ''времени открытия'';<br />
<br />
- ''first'' - это состояние перезапускает текст без появления по ''alpha''; в этом состоянии текстовый объект мгновенно отобразит первую (или единственную) страницу текста; <br />
<br />
- ''next'' - в этом состоянии текстовый объект мгновенно отобразит следующую за текущей страницу текста (если текущая страница - последняя, то в этом состоянии ничего не произойдет);<br />
<br />
- ''close'' - плавно растворяет текст до ''alpha=0'' в течении ''времени закрытия'', после чеге переходит в состояние ''end'';<br />
<br />
- ''end'' - в этом состоянии текстовый объект не отображается.<br />
<br />
'''!!! - Необходимо обязательно сохранять любые изменения с текстом в редакторе TextEditor.'''<br />
<br />
[[Файл:Text1.PNG|800px|thumb|center]]<br />
<br />
=== Дополнительные параметры ===<br />
<br />
[[Файл:Text2.PNG|800px|thumb|right]] <br />
<br />
'''Группа - форматирования'''<br />
<br />
*'''dx''' - Бордюр (отступ текста слева и справа от границы прямоугольника объекта);<br />
*'''dy''' - Бордюр (отступ текста сверху и снизу от границы прямоугольника объекта);<br />
*'''отступ''' - Вертикальное расстояние между строчками в пикселях;<br />
*'''h align''' - Горизонтальное форматирование. Если (c) - центрирование по горизонтали, если (r) - прижатие вправо;<br />
*'''v align''' - Вертикальное форматирование. Если (c) - центрирование по вертикали.<br />
[[Файл:2224.png|250px|center]]<br />
[[Файл:Text11.png|250px|left]]<br />
[[Файл:Text22.png|250px|center]]<br />
<br><br />
<br />
'''Группа - Параметры отображения текста'''<br />
<br />
*'''время до открытия''' - Время перед началом проявления текста (от невидимого до заданной прозрачности);<br />
*'''время открытия''' - Время проявления текста и подложки до alpha в начале;<br />
*'''время закрытия''' - Время исчезновения текста и подложки от alpha до 0 в конце. Если отрицательно - текст не закрывается;<br />
*'''буквы''' - Задержка в ms для перехода к новой букве при подсветке;<br />
*'''слова''' - Задержка в ms перед подсветкой следующего слова;<br />
*'''страницы''' - Задержка в ms перед переходом к следующей странице или увяданию по alpha-каналу.<br />
<br />
'''Группа - Параметры используемого [[шрифт]]а'''<br />
<br />
*'''имя''' - Номер [[шрифт]]а - целое число, начиная с 0 (порядковый номер шрифта).<br />
*'''размер''' - Размер [[шрифт]]а в поинтах.<br />
*'''цвет 1''' - Цвет текста начального вида (бледный).<br />
*'''цвет 2''' - Цвет прочитанного текста (контрастный). Чтение делается по буквам.<br />
<br />
'''Группа - Параметры поведения текста'''<br />
<br />
*'''автопромотка''' - Автоматический переход на следующую страницу после завершения отображения текста;<br />
* '''зациклить''' - Зациклить страницы (после последней, перейти опять на первую);<br />
*'''подсветка''' - Тип подсветки: <br />
**0-не подсвечивать, <br />
**1-по слову; <br />
**2-по букве слова (караоке); <br />
**3-по букве с начала страницы.<br />
*'''звук''' - 1 - есть озвучка, 0 - нет;<br />
*'''случайный выбор''' - 1 - при переключении страницы будет выбираться случайная, 0 - все страницы последовательно. Если выбрана 1 - в редакторе Texts Editor между страницами надо поставить знак #. <br />
<br>Например:<br />
<br />
[[Файл:Text3.PNG|800px|thumb|center]]<br />
<br />
*'''голос''' - голос для озвучки. Звуковой файл для одной реплики.<br />
*'''позиционирование текста'''<br />
** горизонтальное - 0 - нет выравнивания; 1 - прижать к левому краю; 2 - центр; 3 - к правому;<br />
** вертикальное - 0 - нет выравнивания; 1 - прижать к верхнему краю; 2 - центр; 3 - к нижнему.<br />
<br />
=== Добавляемые параметры ===<br />
<br />
<br />
[[Файл:Menadd.png|300px|right]]<br />
Меню выбора ''Добавляемые параметры'' к объектам активируется по правой кнопки мыши. <br />
<br />
[[Файл:+.png]] '''голос для озвучки''' - голос для озвучки 1 реплики. Следить за тем, чтобы количество звуков совпадало с количеством реплик.<br />
<br />
<br />
== Пример применения ==<br />
<br />
[[Файл:Text3.PNG|800px|thumb|center]]<br />
<br />
[[Файл:Ex3.PNG|800px|thumb|center]]<br />
<br />
== Примечания и дополнения ==<br />
<br />
* Если у одного текстового ID слишком много страниц или же они должны меняться в запутанном порядке, то лучше создать несколько тестовых ID и по очереди присваивать их одному текстовому объекту с помощью машины состояний: команда ''set'', параметры ''obj''(текстовый объект), ''par''(txtID), ''val_txt''(текстовый ID, перетаскивается кнопкой мыши из редактора текстов).<br />
* Отображать и делать невидимым текст можно несколькими способами, например, менять общие параметры vis или al, но целесообразней использовать состояния текстового объекта ''start'' и ''close''.<br />
* Разделение строк в текстовой базе символом ''#'' можно использовать, если страниц 2(3). В этом случае для смены страниц используют состояние ''next''. Если страниц больше 2(3), лучше создать несколько текстовых ID и присваивать их текстовому объекту с помощью машины состояний.<br />
* Значения временных параметров по умолчанию: <br />
:время до открытия - 0, <br />
:время открытия - 500,<br />
:время закрытия - 500, <br />
:буквы - 30, <br />
:слова - 30, <br />
:страницы - 500. <br />
:Другими словами такие значения параметров равносильны нулю.<br />
'''Для постепенного открытия (закрытия) текста следует указывать временные параметры отличные от значений по умолчанию.'''</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Text11.png&diff=5093Файл:Text11.png2013-08-30T12:55:08Z<p>Atonkonog: загружена новая версия «Файл:Text11.png»</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Text22.png&diff=5092Файл:Text22.png2013-08-30T12:46:22Z<p>Atonkonog: загружена новая версия «Файл:Text22.png»: слово точка пишется без мягкого знака</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Text11.png&diff=5091Файл:Text11.png2013-08-30T12:45:38Z<p>Atonkonog: загружена новая версия «Файл:Text11.png»: слово точка пишется без мягкого знака</p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Text&diff=5088Text2013-08-30T09:17:43Z<p>Atonkonog: /* Параметры и модификаторы */</p>
<hr />
<div>== Введение ==<br />
[[Файл:2223.png]]<br><br />
Для отображения текстовой информации с поддержкой многоязычности. Для управления текстовыми ресурсами используется TextEditor. <br><br />
<br />
Если необходимо разместить текст на сцене необходимо создать объект с типом text и перетащить на поле текстID текстовую строку из TextEditor. Также можно просто перенести их TextEditor выбранную текстовую запись, при этом автоматически создастся объект с типом Text.<br><br />
<br />
<br />
== Параметры объекта ==<br />
<br />
=== Общие параметры ===<br />
(см. описание [[Object|Object]])<br />
<br />
=== Основные параметры ===<br />
<br />
*'''res''' - Графический ресурс подложки на которой выводится текст. Перетаскивается мышкой из редактора текста (поле должно находится в состоянии редактирования). Может отсутствовать.<br />
*'''текстID''' - Выводимый текст перетаскивается из ресурса тектстов, для перетягивания поле в объекте Text должно быть в режиме редактирования. Решетка (#) разделяет на страницы, черта (|) - принудительный переход на новую строку.<br />
*'''текст''' - Выводимый текст без использования базы текстовых ресурсов. Решетка (#) разделяет на страницы, черта (|) - принудительный переход на новую строку.<br />
*'''состояние''' - в поле указывается состояние текстового объекта, в которое он перейдет при загрузке экрана (это поле часто оставляют пустым, а состояния задают машиной). Состояния текстового объекта:<br />
<br />
- ''start'' - это состояние проверяет время ''до открытия'' и переходит либо в ''beg'', если время до открытия не ноль, либо в ''open'', если время до открытия равняется нулю;<br />
<br />
- ''beg'' - это состояние "ждет" время ''до открытия'' и переходит в ''open'';<br />
<br />
- ''open'' - плавно проявляет текст до его нормального ''alpha'' в течении ''времени открытия'';<br />
<br />
- ''first'' - это состояние перезапускает текст без появления по ''alpha''; в этом состоянии текстовый объект мгновенно отобразит первую (или единственную) страницу текста; <br />
<br />
- ''next'' - в этом состоянии текстовый объект мгновенно отобразит следующую за текущей страницу текста (если текущая страница - последняя, то в этом состоянии ничего не произойдет);<br />
<br />
- ''close'' - плавно растворяет текст до ''alpha=0'' в течении ''времени закрытия'', после чеге переходит в состояние ''end'';<br />
<br />
- ''end'' - в этом состоянии текстовый объект не отображается.<br />
<br />
'''!!! - Необходимо обязательно сохранять любые изменения с текстом в редакторе TextEditor.'''<br />
<br />
[[Файл:Text1.PNG|800px|thumb|center]]<br />
<br />
=== Дополнительные параметры ===<br />
<br />
[[Файл:Text2.PNG|800px|thumb|right]] <br />
<br />
'''Группа - форматирования'''<br />
<br />
*'''dx''' - Бордюр (отступ текста слева и справа от границы прямоугольника объекта);<br />
*'''dy''' - Бордюр (отступ текста сверху и снизу от границы прямоугольника объекта);<br />
*'''отступ''' - Вертикальное расстояние между строчками в пикселях;<br />
*'''h align''' - Горизонтальное форматирование. Если (c) - центрирование по горизонтали, если (r) - прижатие вправо;<br />
*'''v align''' - Вертикальное форматирование. Если (c) - центрирование по вертикали.<br />
[[Файл:2224.png|250px|center]]<br />
[[Файл:Text11.png|250px|left]]<br />
[[Файл:Text22.png|250px|center]]<br />
<br><br />
<br />
'''Группа - Параметры отображения текста'''<br />
<br />
*'''время до открытия''' - Время перед началом проявления текста (от невидимого до заданной прозрачности);<br />
*'''время открытия''' - Время проявления текста и подложки до alpha в начале;<br />
*'''время закрытия''' - Время исчезновения текста и подложки от alpha до 0 в конце. Если отрицательно - текст не закрывается;<br />
*'''буквы''' - Задержка в ms для перехода к новой букве при подсветке;<br />
*'''слова''' - Задержка в ms перед подсветкой следующего слова;<br />
*'''страницы''' - Задержка в ms перед переходом к следующей странице или увяданию по alpha-каналу.<br />
<br />
'''Группа - Параметры используемого [[шрифт]]а'''<br />
<br />
*'''имя''' - Номер [[шрифт]]а - целое число, начиная с 0 (порядковый номер шрифта).<br />
*'''размер''' - Размер [[шрифт]]а в поинтах.<br />
*'''цвет 1''' - Цвет текста начального вида (бледный).<br />
*'''цвет 2''' - Цвет прочитанного текста (контрастный). Чтение делается по буквам.<br />
<br />
'''Группа - Параметры поведения текста'''<br />
<br />
*'''автопромотка''' - Автоматический переход на следующую страницу после завершения отображения текста;<br />
* '''зациклить''' - Зациклить страницы (после последней, перейти опять на первую);<br />
*'''подсветка''' - Тип подсветки: <br />
**0-не подсвечивать, <br />
**1-по слову; <br />
**2-по букве слова (караоке); <br />
**3-по букве с начала страницы.<br />
*'''звук''' - 1 - есть озвучка, 0 - нет;<br />
*'''случайный выбор''' - 1 - при переключении страницы будет выбираться случайная, 0 - все страницы последовательно. Если выбрана 1 - в редакторе Texts Editor между страницами надо поставить знак #. <br />
<br>Например:<br />
<br />
[[Файл:Text3.PNG|800px|thumb|center]]<br />
<br />
*'''голос''' - голос для озвучки. Звуковой файл для одной реплики.<br />
*'''позиционирование текста'''<br />
** горизонтальное - 0 - нет выравнивания; 1 - прижать к левому краю; 2 - центр; 3 - к правому;<br />
** вертикальное - 0 - нет выравнивания; 1 - прижать к верхнему краю; 2 - центр; 3 - к нижнему.<br />
<br />
== Пример применения ==<br />
<br />
[[Файл:Text3.PNG|800px|thumb|center]]<br />
<br />
[[Файл:Ex3.PNG|800px|thumb|center]]<br />
<br />
<br />
== Примечания и дополнения ==<br />
<br />
* Если у одного текстового ID слишком много страниц или же они должны меняться в запутанном порядке, то лучше создать несколько тестовых ID и по очереди присваивать их одному текстовому объекту с помощью машины состояний: команда ''set'', параметры ''obj''(текстовый объект), ''par''(txtID), ''val_txt''(текстовый ID, перетаскивается кнопкой мыши из редактора текстов).<br />
* Отображать и делать невидимым текст можно несколькими способами, например, менять общие параметры vis или al, но целесообразней использовать состояния текстового объекта ''start'' и ''close''.<br />
* Разделение строк в текстовой базе символом ''#'' можно использовать, если страниц 2(3). В этом случае для смены страниц используют состояние ''next''. Если страниц больше 2(3), лучше создать несколько текстовых ID и присваивать их текстовому объекту с помощью машины состояний.<br />
* Значения временных параметров по умолчанию: <br />
:время до открытия - 0, <br />
:время открытия - 500,<br />
:время закрытия - 500, <br />
:буквы - 30, <br />
:слова - 30, <br />
:страницы - 500. <br />
:Другими словами такие значения параметров равносильны нулю.<br />
'''Для постепенного открытия (закрытия) текста следует указывать временные параметры отличные от значений по умолчанию.'''</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Array_example.jpg&diff=4343Файл:Array example.jpg2013-06-21T15:26:01Z<p>Atonkonog: </p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4342Machine2013-06-21T15:23:22Z<p>Atonkonog: /* Также массив обладает состояниями: */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
Для проверки текущего значения прозрачности у объекта можно воспользоваться параметром ''cur_al''<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Свойства объекта массив: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
=== Состояния объекта массив: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4341Machine2013-06-21T15:22:51Z<p>Atonkonog: /* Массив обладает следующими свойствами: */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
Для проверки текущего значения прозрачности у объекта можно воспользоваться параметром ''cur_al''<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Свойства объекта массив: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4299Machine2013-06-18T10:07:12Z<p>Atonkonog: /* Random 2 */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4298Machine2013-06-18T10:06:38Z<p>Atonkonog: /* Random-псевдо */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<pre><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4297Machine2013-06-18T10:05:28Z<p>Atonkonog: /* Исходный XML код */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<pre><br />
<obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj><br />
</pre><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4293Machine2013-06-17T18:11:27Z<p>Atonkonog: /* Копирование объекта */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра. Копировать следует через использование доп. сцены (см. выше)<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<nowiki><obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj></nowiki><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4292Machine2013-06-17T18:10:35Z<p>Atonkonog: /* Random */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Копирование машины состояния с сохранением ссылки на себя ==<br />
Довольно часто бывает, что машина состояний ссылается только на глобальные объекты и на саму себя. При этом, если мы просто скопируем объект, он будет ссылаться на свою предыдущую копию. Этого можно избежать, сделав 3 шага:<br />
1. Переместить объект в отдельную сцену<br />
2. Скопировать данную сцену(имеется в виду обычное копирование, без ссылки)<br />
3. Перенести объект и его копию обратно, в нужную сцену<br />
4. Созданые сцены можно удалить :)<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<nowiki><obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj></nowiki><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Array.jpg&diff=4291Файл:Array.jpg2013-06-17T17:58:52Z<p>Atonkonog: </p>
<hr />
<div></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4290Machine2013-06-17T17:58:10Z<p>Atonkonog: /* Массив (Array) */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<nowiki><obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj></nowiki><br />
<br />
=== Машина состояний объекта ===<br />
[[Файл:array.jpg]]</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=4289Machine2013-06-17T17:56:48Z<p>Atonkonog: /* Guest */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение;<br />
** '''[[#spline|spline]]''' - движение по сплайну (по кривой).<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''rev''' - играть анимацию в обратном порядке; 0 - прямой порядок проигрывания, 1 - обратный порядок проигрывания;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br>Если есть анимация открывающейся и закрывающейся книги (коробки, двери и т.д.) не обязательно подгружать в проект две анимации, можно использовать одну, но запускать ее в обратном порядке, для этого есть параметр '''rev'''.<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
=== spline ===<br />
<br />
Сплайн позволяет перемещать машину по заранее заданной траектории.<br />
<br />
====Параметры====<br />
<br />
*'''key''' - точки сплайна по которым движется <br />
*'''t''' - время движения по траектории<br />
*'''go''' - по окончанию переход в состояние<br />
*'''if''' - условие перехода<br />
*'''loop''' - количество повторений<br />
*'''break''' - первать команды на этой<br />
*'''wait''' - номер запускаемого действия<br />
*'''init''' - номер запускаемого действия<br />
*'''alpha''' - номер запускаемого действия<br />
*'''rot''' - номер запускаемого действия<br />
*'''move''' - номер запускаемого действия<br />
*'''set''' - номер запускаемого действия<br />
*'''phys''' - номер запускаемого действия<br />
<br />
====Построение сплайна====<br />
<br />
# в состоянии машины добавляем правой кнопкой мыши действие "spline"<br />
# добавляем минимально необходимые параметры: '''key''' и '''t''', указываем время движения в '''t'''<br />
# выделяем для редактирования поле '''key'''<br />
# записываем координаты точек через запятую, сначала x потом y, например: -211,-248,-151,-248,-91,-247,59,-246,60,101,60,159,1,190<br />
Если записали все координаты вручную, то можно сохранить и проверять.<br />
Или можно в окне списка состояний нажимаем на кнопку "build spline" (справа вверху).<br />
[[Файл:Btn spline.jpg|500px]]<br />
<br />
Окно с списком состояний закроется, появится дополнительная панель с настройками сплайна и появится возможность указывать мышкой по экрану точки для сплайна.<br />
<br />
[[Файл:Spline panel.jpg|500px]]<br />
<br />
Точки сплайна указываются кликом левой кнопки мыши по экрану.<br />
<br />
Возможности редактирования:<br />
<br />
'''режимы:'''<br />
*'''add''' - по нажатию левой кнопкой мыши по экрану - будет добавлена новая точка, которая соеденится с предидущей<br />
*'''select''' - по нажатию левой кнопкой мыши по точке сплайна появится возможность отредактировать её положение перетащив её или поменяв её координаты в полях x и у<br />
*'''delete''' - по нажатию левой кнопкой мыши по точке сплайна точка удалится<br />
<br />
Чтобы удалить все точки сплайна необходимо нажать на кнопку "'''delete all knots'''"<br />
<br />
Сохранить сплайн можно нажав на кнопку "'''Save spline'''"<br />
<br />
<br />
====Дополнительные сведения====<br />
<br />
* Время движения между двумя соседними точками всегда одинаково, то есть чем дальше друг от друга соседние точки, тем быстрее будет двигаться объект, чем ближе - тем медленней.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.<br />
<br />
<br />
== Guest ==<br />
<br />
'''Guest (гость)''' - объект, который перевел машину в текущее состояние. Пример: кнопка ''btn1'' по клику переводит машину ''mch1'' в состояние ''st1'', в этом состоянии у машины ''mch1'' гостем является кнопка ''btn1''. Гостем может быть объект любого типа, если он может менять состояние другому объекту (например: хидден-объект по нахождению может менять состояние объекту, кнопка, машина, пэчворк и т.д.)<br />
<br />
В машине состояний можно считывать (проверять) и передавать параметры и состояния гостя. Любое поле ''obj'' в выпадающем списке содержит строку ''guest'', что позволяет работать с гостем, как с любым другим объектом.<br />
<br />
=== Пример использования ===<br />
<br />
[[Файл:Guest1.jpg|left]]<br />
Пускай экран содержит 3 кнопки (''btn1'', ''btn2'' и ''btn3'') и одну машину ''mch1''. Нужно сделать так, чтобы по клику на любую из кнопок машина перемещалась в ее координаты и переводила кнопку в состояние ''disable''. Так же по клику на кнопку ''btn2'', машина должна перейти в состояние ''bonus''.<br><br />
Всем трем кнопкам по клику пропишем передавать объекту ''mch1'' состояние ''check''.<br><br><br />
Создадим в машине три состояния: ''init'' - состояние в котором машина будет находиться по умолчанию, ''check'' - состояние, которое будет вызываться тремя кнопками, в этом состоянии у машины ''mch1'' одна из трех кнопок будет гостем, ''bonus'' - последнее состояние.<br><br />
Две команды ''var'' считывают у гостя координаты, т.к. мы не знаем, какая именно кнопка перевела машину ''mch1'' в состояние ''check'', то обращаемся к гостю, а не к кнопкам. За ними следует две команды ''set'', которые передают координаты гостя машине. Еще один ''set'' переводит гостя в состояние ''disable''. И через ''wait'' осуществляется переход в состояние ''bonus'', если гость ''btn2''.<br />
<br />
<pre><br />
При смене состояния гость сохраняется, т.е. в состоянии bonus гостем останется btn2.<br />
</pre><br />
<pre><br />
Если машина изначально сама себе меняет состояния, то у нее нет гостя.<br />
</pre><br />
<br />
[[Файл:Guest2.jpg]]<br />
<br />
== Массив (Array) ==<br />
<br />
В данном объекте реализован массив, имеющий максимальную длинну в 20 элементов.<br />
<br />
=== Массив обладает следующими свойствами: ===<br />
<br />
len - длинна массива. Длинна массива может как считываться, так и записываться. Влияет на количество сохраняемых объектов в Options.<br />
<br />
index1 - индекс элемента. (данный массив можно расширить до многомерного и использовать несколько индексов)<br />
<br />
val - значение элемента массива, с индексом index1<br />
<br />
a1..a20 - внутренние элементы массива(обращаться можно через свойство par объекта). Предполагается, что пользователь редактора к ним обращаться напрямую не будет, однако иногда для удобства полезны.<br />
<br />
<br />
=== Также массив обладает состояниями: ===<br />
<br />
get - при вызове этого состояния во внутреннюю переменную val записывается значение элемента с индексом index1<br />
<br />
set - при вызове этого состояния во внутреннюю переменную a1..a20, соответствующую индексу index1 записывается значение val<br />
<br />
load - загрузить значения массива из xml.<br />
<br />
save - сохранить элементы массива от 1 до len<br />
<br />
=== Как использовать? ===<br />
<br />
1. Загружаем массив, переводя объект array в состояние load<br />
<br />
2. Записываем значения массива<br />
<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, в которую будет заноситься число)<br />
б). Задаём значение свойству val объекта array (устанавливаем значение, которое будет заноситься в ячейку с индексом index1)<br />
в). Переводим объект array в состояние set<br />
<br />
3. Считываем значения массива<br />
а). Задаём значение свойству index1 объекта array (устанавливаем индекс ячейки, из которой будет считываться число)<br />
б). Переводим объект array в состояние get<br />
в). Считываем значение из свойства val объекта array<br />
<br />
4. Сохраняем массив, переводя объект array в состояние save. Если хотите изменить количество сохраняемых эелментов - предварительно измените параметр len.<br />
<br />
=== Копирование объекта ===<br />
<br />
При копировании, необходимо заменить в состояниях load и save array.имя_параметра на другое имя. Например, array2.имя_параметра<br />
<br />
=== Достоинства ===<br />
<br />
Позволяет избежать необходимости каждый раз создавать большое количество if-ов и set-ов, если необходимо работать с нумерованным списком. Можно один раз создать структуру и копировать её неограниченное количество раз<br />
<br />
=== Недостатки ===<br />
<br />
Данный объект содержит довольно большое количество кода, поэтому при большом их обилии/длинне может занизить скорость работы сцены и скорость загрузки сцены.<br />
<br />
=== Исходный XML код===<br />
Прим. id="369" - идентификатор объекта Options, сохраняющего все переменные приложения. id="7845" - идентификатор объекта<br />
<br />
<nowiki><obj id="7845" type="machine" nm="array" sync="1" w="1" h="1"><br />
<st id="init"/><br />
<st id="get"><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="7845" par="val" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="val" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="val" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="val" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="val" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="val" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="val" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="val" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="val" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="val" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="val" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="val" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="val" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="val" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="val" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="val" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="val" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="val" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="val" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="val" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="set"><br />
<var nm="val" obj="7845" par="val"/><br />
<set obj="7845" par="a1" val="(val)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(val)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(val)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(val)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(val)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(val)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(val)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(val)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(val)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(val)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(val)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(val)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(val)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(val)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(val)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(val)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(val)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(val)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(val)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(val)" round="1" if="19"/><br />
<if obj="7845" par="index1" val="1"/><br />
<if obj="7845" par="index1" val="2"/><br />
<if obj="7845" par="index1" val="3"/><br />
<if obj="7845" par="index1" val="4"/><br />
<if obj="7845" par="index1" val="5"/><br />
<if obj="7845" par="index1" val="6"/><br />
<if obj="7845" par="index1" val="7"/><br />
<if obj="7845" par="index1" val="8"/><br />
<if obj="7845" par="index1" val="9"/><br />
<if obj="7845" par="index1" val="10"/><br />
<if obj="7845" par="index1" val="11"/><br />
<if obj="7845" par="index1" val="12"/><br />
<if obj="7845" par="index1" val="13"/><br />
<if obj="7845" par="index1" val="14"/><br />
<if obj="7845" par="index1" val="15"/><br />
<if obj="7845" par="index1" val="16"/><br />
<if obj="7845" par="index1" val="17"/><br />
<if obj="7845" par="index1" val="18"/><br />
<if obj="7845" par="index1" val="19"/><br />
<if obj="7845" par="index1" val="20"/><br />
</st><br />
<st id="load"><br />
<var nm="a1" obj="369" par="array.a1" user="1"/><br />
<var nm="a2" obj="369" par="array.a2" user="1"/><br />
<var nm="a3" obj="369" par="array.a3" user="1"/><br />
<var nm="a4" obj="369" par="array.a4" user="1"/><br />
<var nm="a5" obj="369" par="array.a5" user="1"/><br />
<var nm="a6" obj="369" par="array.a6" user="1"/><br />
<var nm="a7" obj="369" par="array.a7" user="1"/><br />
<var nm="a8" obj="369" par="array.a8" user="1"/><br />
<var nm="a9" obj="369" par="array.a9" user="1"/><br />
<var nm="a10" obj="369" par="array.a10" user="1"/><br />
<var nm="a11" obj="369" par="array.a11" user="1"/><br />
<var nm="a12" obj="369" par="array.a12" user="1"/><br />
<var nm="a13" obj="369" par="array.a13" user="1"/><br />
<var nm="a14" obj="369" par="array.a14" user="1"/><br />
<var nm="a15" obj="369" par="array.a15" user="1"/><br />
<var nm="a16" obj="369" par="array.a16" user="1"/><br />
<var nm="a17" obj="369" par="array.a17" user="1"/><br />
<var nm="a18" obj="369" par="array.a18" user="1"/><br />
<var nm="a19" obj="369" par="array.a19" user="1"/><br />
<var nm="a20" obj="369" par="array.a20" user="1"/><br />
<set obj="7845" par="a1" val="(a1)" round="1" if="0"/><br />
<set obj="7845" par="a2" val="(a2)" round="1" if="1"/><br />
<set obj="7845" par="a3" val="(a3)" round="1" if="2"/><br />
<set obj="7845" par="a4" val="(a4)" round="1" if="3"/><br />
<set obj="7845" par="a5" val="(a5)" round="1" if="4"/><br />
<set obj="7845" par="a6" val="(a6)" round="1" if="5"/><br />
<set obj="7845" par="a7" val="(a7)" round="1" if="6"/><br />
<set obj="7845" par="a8" val="(a8)" round="1" if="7"/><br />
<set obj="7845" par="a9" val="(a9)" round="1" if="8"/><br />
<set obj="7845" par="a10" val="(a10)" round="1" if="9"/><br />
<set obj="7845" par="a11" val="(a11)" round="1" if="10"/><br />
<set obj="7845" par="a12" val="(a12)" round="1" if="11"/><br />
<set obj="7845" par="a13" val="(a13)" round="1" if="12"/><br />
<set obj="7845" par="a14" val="(a14)" round="1" if="13"/><br />
<set obj="7845" par="a15" val="(a15)" round="1" if="14"/><br />
<set obj="7845" par="a16" val="(a16)" round="1" if="15"/><br />
<set obj="7845" par="a17" val="(a17)" round="1" if="16"/><br />
<set obj="7845" par="a18" val="(a18)" round="1" if="17"/><br />
<set obj="7845" par="a19" val="(a19)" round="1" if="18"/><br />
<set obj="7845" par="a20" val="(a20)" round="1" if="19"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
<st id="save"><br />
<var nm="len" obj="7845" par="len"/><br />
<var nm="a1" obj="7845" par="a1"/><br />
<var nm="a2" obj="7845" par="a2"/><br />
<var nm="a3" obj="7845" par="a3"/><br />
<var nm="a4" obj="7845" par="a4"/><br />
<var nm="a5" obj="7845" par="a5"/><br />
<var nm="a6" obj="7845" par="a6"/><br />
<var nm="a7" obj="7845" par="a7"/><br />
<var nm="a8" obj="7845" par="a8"/><br />
<var nm="a9" obj="7845" par="a9"/><br />
<var nm="a10" obj="7845" par="a10"/><br />
<var nm="a11" obj="7845" par="a11"/><br />
<var nm="a12" obj="7845" par="a12"/><br />
<var nm="a13" obj="7845" par="a13"/><br />
<var nm="a14" obj="7845" par="a14"/><br />
<var nm="a15" obj="7845" par="a15"/><br />
<var nm="a16" obj="7845" par="a16"/><br />
<var nm="a17" obj="7845" par="a17"/><br />
<var nm="a18" obj="7845" par="a18"/><br />
<var nm="a19" obj="7845" par="a19"/><br />
<var nm="a20" obj="7845" par="a20"/><br />
<set obj="369" par="array.a1" val="(a1)" round="1" user="1" if="0"/><br />
<set obj="369" par="array.a2" val="(a2)" round="1" user="1" if="1"/><br />
<set obj="369" par="array.a3" val="(a3)" round="1" user="1" if="2"/><br />
<set obj="369" par="array.a4" val="(a4)" round="1" user="1" if="3"/><br />
<set obj="369" par="array.a5" val="(a5)" round="1" user="1" if="4"/><br />
<set obj="369" par="array.a6" val="(a6)" round="1" user="1" if="5"/><br />
<set obj="369" par="array.a7" val="(a7)" round="1" user="1" if="6"/><br />
<set obj="369" par="array.a8" val="(a8)" round="1" user="1" if="7"/><br />
<set obj="369" par="array.a9" val="(a9)" round="1" user="1" if="8"/><br />
<set obj="369" par="array.a10" val="(a10)" round="1" user="1" if="9"/><br />
<set obj="369" par="array.a11" val="(a11)" round="1" user="1" if="10"/><br />
<set obj="369" par="array.a12" val="(a12)" round="1" user="1" if="11"/><br />
<set obj="369" par="array.a13" val="(a13)" round="1" user="1" if="12"/><br />
<set obj="369" par="array.a14" val="(a14)" round="1" user="1" if="13"/><br />
<set obj="369" par="array.a15" val="(a15)" round="1" user="1" if="14"/><br />
<set obj="369" par="array.a16" val="(a16)" round="1" user="1" if="15"/><br />
<set obj="369" par="array.a17" val="(a17)" round="1" user="1" if="16"/><br />
<set obj="369" par="array.a18" val="(a18)" round="1" user="1" if="17"/><br />
<set obj="369" par="array.a19" val="(a19)" round="1" user="1" if="18"/><br />
<set obj="369" par="array.a20" val="(a20)" round="1" user="1" if="19"/><br />
<set obj="369" par="array.len" val="(len)" round="1" user="1"/><br />
<if obj="7845" par="len" op="&gt;" val="0"/><br />
<if obj="7845" par="len" op="&gt;" val="1"/><br />
<if obj="7845" par="len" op="&gt;" val="2"/><br />
<if obj="7845" par="len" op="&gt;" val="3"/><br />
<if obj="7845" par="len" op="&gt;" val="4"/><br />
<if obj="7845" par="len" op="&gt;" val="5"/><br />
<if obj="7845" par="len" op="&gt;" val="6"/><br />
<if obj="7845" par="len" op="&gt;" val="7"/><br />
<if obj="7845" par="len" op="&gt;" val="8"/><br />
<if obj="7845" par="len" op="&gt;" val="9"/><br />
<if obj="7845" par="len" op="&gt;" val="10"/><br />
<if obj="7845" par="len" op="&gt;" val="11"/><br />
<if obj="7845" par="len" op="&gt;" val="12"/><br />
<if obj="7845" par="len" op="&gt;" val="13"/><br />
<if obj="7845" par="len" op="&gt;" val="14"/><br />
<if obj="7845" par="len" op="&gt;" val="15"/><br />
<if obj="7845" par="len" op="&gt;" val="16"/><br />
<if obj="7845" par="len" op="&gt;" val="17"/><br />
<if obj="7845" par="len" op="&gt;" val="18"/><br />
<if obj="7845" par="len" op="&gt;" val="19"/><br />
</st><br />
</obj></nowiki></div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9A%D0%BD%D0%B8%D0%B3%D0%B0_%D0%B6%D0%B0%D0%BB%D0%BE%D0%B1_%D0%B8_%D0%BF%D0%BE%D0%B6%D0%B5%D0%BB%D0%B0%D0%BD%D0%B8%D0%B9&diff=3822Книга жалоб и пожеланий2013-04-30T15:56:46Z<p>Atonkonog: /* Новые объекты и свойства */</p>
<hr />
<div>Внимание !!<br />
* Перед публикацией внимательно читать ВСЕ!<br />
* Делаем при обсуждении отступы (двоеточие) и подписываемся (4 тильды).<br />
<br />
== Улучшение интерфейса ==<br />
<br />
* Возможность копирования состояний из машины в машину.--[[Участник:Oilich|Oilich]] 13:36, 24 января 2013 (CET)<br />
* Поворачивать, масштабировать объекты прямо на сцене (как в любом граф.редакторе) [[Участник:Steps|Steps]] 14:11, 24 января 2013 (CET)<br />
* Добавить горячие клавиши в состоянии машин. В выбранном состоянии машины, например если нажать "w" создается ф-я wait, "i"=if,<br> "m" = move, "s" = set ну и так далее. --[[Участник:Igood|Igood]] 16:10, 24 января 2013 (CET)<br />
:: С какой клавишей использовать CTRL +S сохранение + давайте уже весь список хоткеев. Проще разнести и реализовать.\<br />
<br />
* Возможность копирования ф-й(set,wait...) из одного состояния машины в другую.--[[Участник:Igood|Igood]] 16:12, 24 января 2013 (CET)<br />
:: В чем отличие от "Возможность копирования состояний из машины в машину.--[[Участник:Oilich|Oilich]] 13:36, 24 января 2013 (CET)"<br />
::: В том что это не состояния а отдельные функции в состоянии.--[[Участник:Igood|Igood]] 08:53, 25 января 2013 (CET)<br />
:::: я поддерживаю. мелочь, а приятно. [[Участник:Steps|Steps]] 12:13, 25 января 2013 (CET)<br />
<br />
* Добавить событие кнопке, изм. состояния объекта если на нее нажали в состоянии disable.--[[Участник:Igood|Igood]] 16:18, 24 января 2013 (CET)<br />
<br />
:: С точки зрения кнопки - Она "Кнопка" имеет два состояния, в состоянии disable кнопка не должна вообще воспринимать кликов. Но если всех это не запутает и нужно для космического корабля то ОК--[[Участник:Boyarin|Boyarin]] 21:45, 24 января 2013 (CET)<br />
:: Стоит обсудить. Действительно, не очень логично считать дизейбл рабочим состоянием. [[Участник:Steps|Steps]] 12:16, 25 января 2013 (CET)<br />
<br />
* Добавить возможность открывать несколько машин состояний одновременно. Сделать так, чтоб их можно было сворачивать.--[[Участник:Fhod|Fhod]] 17:00, 25 января 2013 (CET)<br />
<br />
<br />
* По логике в списке сначала должен идти параметр, а потом его значение.--[[Участник:Avereskun|Avereskun]] 10:06, 25 января 2013 (CET)<br />
<br />
[[Файл:Editor123.jpg]]<br />
<br />
* В редакторе сцен, если закрыл окно с параметрами или деревом объектов, то его можно вернуть только переоткрыв редактор. Необходимо добавить управление отображением этих окон из меню. --[[Участник:Shejko|Shejko]] 09:22, 29 января 2013 (CET) <br />
: Ну не совсем так. Правой кнопкой на панели и галкой можно включить область с деревом и проперти - Но понятно что требует в настройки вынести --[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить возможность одновременно синхронизировать и снимать синхронизацию с группы объектов.--[[Участник:Odyadina|Odyadina]] 13:54, 29 января 2013 (CET)<br />
: Согласен + можно подумать и про др груп изменения--[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить синхронизацию (да-нет) свойств сцены --[[Участник:Odyadina|Odyadina]] 10:59, 30 января 2013 (CET)<br />
: согласен--[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить возможность хранить проекты на разных дисках, не привязываясь к местонахождению редактора.<br />
Нужно с этим что-то делать:<br />
[[Файл:Файл_проекта.JPG|200px|thumb|left|описание]]<br />
<br clear="all" /><br />
--[[Участник:Dorl|Dorl]] 09:02, 31 января 2013 (CET)<br />
<br />
* Возможность добавлять графические объекты с применением к ним свойств объектов, которые уже заданы аниматором, а именно параметры кнопок, чекбоксов, НО НЕ КООРДИНАТЫ. Чтобы работало по типу пипетки--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET). <br />
<br />
Потому как часто возникает вопрос коррекции сцены с перемещением (также увеличением-уменьшением, вращением, заменой цвета и т.д.), например, тех же кнопок для улучшения общего вида сцены--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET). <br />
<br />
Во-первых - облегчит работу аниматору (не нужно будет искать новое расположение исправленного объекта), во-вторых - объект будет обладать уже заданными параметрами, в-третьих - расположение изображения будет соответствовать тому, как задумал графический дизайнер--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET).<br />
<br />
<br />
* Добавить кнопку "снять все выделения" и "выделить всё" в окно управления предзагрузкой на кнопках.<br />
<br />
[[Файл:Wind preload button.jpg|150px|thumb|left|окно в которое добавить кнопки]]<br />
<br />
<br clear="all" /><br />
--[[Участник:Shejko|Shejko]] 14:40, 13 февраля 2013 (CET)<br />
<br />
* После добавления дополнительных возможностей объекта не перемещать в начало списка параметров. Я добавляю возможность в объект в конец списка его параметров, скажем в пазл, после добавления параметра меня автоматически бросает вверх списка и чтобы поменять параметры приходится снова опускаться к добавленному параметру.<br />
<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
* Добавить кнопку "развернуть всё" в списке параметров объектов.<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
* Также в добавляемых возможностях объекта, таких как "изменить графический id", где всего 3 параметра и в любом случае для работы этого параметра необходимо заполнить все 3 поля, при добавлении возможности лучше было бы если все 3 параметра добавляются автоматически и если один из них не задал - не убирать поле после переоткрытия проекта - его всё равно придётся добавлять.<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
*Добавить для редактора текстовых ресурсов, как в редакторе ресурсов, пункт меню View с подпунктом Always on Top.Было очень актуально при работе с хиддн объектами.<br />
--[[Участник:lkunica|lkunica]] 16:40, 6 марта 2013 (CET)<br />
<br />
*Возможность поменять графический ресурс не перетаскивая его. Для этого программист редактора в поле "res" прописывает имя изображения. При этом, редактор производит поиск и подставляет первое изображение, соответствующее данному имени. Если не находит - выдаёт ошибку.<br />
--[[Участник:Atonkonog|Atonkonog]] 15:40, 18 марта 2013 (CET)<br />
** а если имен изображений несколько, что тогда? какой брать? При перетаскивании привязываем по id а не по имени. --[[Участник:Boyarin|Boyarin]] 07:29, 20 марта 2013 (CET)<br />
*если картинок несколько - берётся первая, которая будет найдена.<br />
--[[Участник:Atonkonog|Atonkonog]] 14:29, 30 апреля 2013 (CEST) <br />
<br />
*Возможность поменять текст не перетаскивая его. Для этого программист редактора в поле "" прописывает имя изображения. При этом, редактор производит поиск и подставляет первую строку, соответствующую данному имени. Если не находит - выдаёт ошибку.<br />
--[[Участник:Atonkonog|Atonkonog]] 15:40, 18 марта 2013 (CET)<br />
** а если имен текстовых объектов несколько, что тогда? ну дальше понятно .... --[[Участник:Boyarin|Boyarin]] 07:29, 20 марта 2013 (CET) <br />
<br />
*Добавить возможность быстро устанавливать следующий/предыдущий текст и графический ресурс в граф. базе ресурсов. Довольно часто бывает, что нужно, например, добавить кучу инвентарных объектов, идентификаторы которых идут последовательно один за другим<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*При копировании машин состояний:<br />
1. Копировать ссылку на самого себя (уже писал, повторяюсь)<br />
2. Если есть вложенные объекты, в новом объекте ссылки должны ссылаться на его подобъекты. Если у объектов есть подобъекты - принцип тоже должен действовать<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*Добавить множественное копирование<br />
Добавить возможность копировать объект несколько раз, при этом, предусмотреть инкрементированную замену параметров объекта(переменные локальные и глобальные, идентификаторы объектов, ресурсов, текстов)<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*Добавить возможность во viewer'e менять любой параметр и состояние любого объекта(простенький дебаг)--[[Участник:Atonkonog|Atonkonog]] 14:45, 26 марта 2013 (CET)<br />
<br />
*Добавить возможность предосмотра текста в объекте текст. Чтобы любое форматирование сразу отображалось. Надоело после каждой правки текста пересохранять весь проект, чтобы увидеть результат.--[[Участник:Amohov|Summer Cat]] 10:51, 1 апреля 2013 (CEST)<br />
<br />
*Добавить возможность менять тип объекта у группы объектов. Например на сцене есть 50 объектов и все они должны быть хидденобъектами. В текущей реализации надо у каждого объекта отдельно менять тип. --[[Участник:Shejko|Shejko]] 08:51, 3 апреля 2013 (CEST)<br />
<br />
*Добавить горячие клавиши для вызова редактора ресурсов и редактора текстов.--[[Участник:Amohov|Summer Cat]] 16:48, 11 апреля 2013 (CEST)<br />
<br />
*Сделать так, чтобы при наведении на объект выбранный в поле '''obj''', в пояснении отображался ''ID'' объекта. Такая возможность позволит избежать ошибок в случаях: <br />
:а) когда вдруг существуют два объекта с одинаковым именем; <br />
:б) когда в поле отображается ''нет'', в этом случае возможны три варианта: объект не выбран, объект с таким ID удален, объект находится на другом экране.--[[Участник:Odyadina|Odyadina]] 12:19, 18 апреля 2013 (CEST)<br />
<br />
*Вынести кнопку "Delete temp data" на панель где кнопки запуска вьювера,базы ресурсов и т.д.--[[Участник:Nbeznosov|Nbeznosov]] 09:13, 26 апреля 2013 (CEST)<br />
<br />
== Новые объекты и свойства==<br />
<br />
* Добавить сплайн (кривая линия), который можно рисовать на сцене и передавать команде move [[Участник:Steps|Steps]] 14:11, 24 января 2013 (CET)<br />
- запланировано--[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
* Добавить в редактор генератор комиксов. Хорошим и простым примером является [http://1001mem.ru/create_comics генератор комиков] Это пожелания на будущее. --[[Участник:Dorl|Dorl]] 10:35, 25 января 2013 (CET)<br />
- все равно не понял --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
* Машина состояний. Добавить в команду '''drag''' распознавания в какую сторону происходит движение (вправо, влево, вниз, вверх) при этом давать возможность менять графический ресурс в зависимости от направления. --[[Участник:Dorl|Dorl]] 16:48, 25 января 2013 (CET)<br />
[[Файл:[[Файл:Drag.JPG|200px|thumb|left|]]<br />
[[Файл:Drag_fish.JPG|200px|thumb|left|]]<br />
<br clear="all" /><br />
* Добавить гибкость работы со шрифтами. Как минимум должна быть: ''возможность наклона'', '''возможность полужирного начертания.''' --[[Участник:Dorl|Dorl]] 09:08, 31 января 2013 (CET)<br />
- покурим, но пока все упирается в лишнюю память<br />
*Когда запущен редактор ресурсов и был свёрнут, то при попытке его запустить снова с панели хорошо бы разворачивать, а не ругаться что он уже запущен.--[[Участник:Amohov|Summer Cat]] 11:00, 20 февраля 2013 (CET)<br />
- согласен--[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Будет очень удобно если вызывать меню методов двойным кликом по этой области, а не по кнопке. Экономит немного времени на разработку проекта.--[[Участник:Amohov|Summer Cat]] 11:11, 20 февраля 2013 (CET)<br />
[[Файл:New addons.PNG|200px|thumb|left|]]<br clear="all" /><br />
*Добавить возможность вызвать редактор ресурсов, когда работаешь с свойствами машины.--[[Участник:Amohov|Summer Cat]] 11:16, 20 февраля 2013 (CET)<br />
- ок --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Выделить несколько объектов и изменить например на машины сразу несколько одним кликом.--[[Участник:Amohov|Summer Cat]] 11:19, 20 февраля 2013 (CET)<br />
- ок --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Когда сильно увеличен экран проекта и мы видим только часть его, хорошо бы на колесо мышки назначить руку для передвижение по экрану, а не пользоваться полосами прокрутки. Это сильно ускорит навигацию по рабочей области а вследствие и разработку.--[[Участник:Amohov|Summer Cat]] 11:24, 20 февраля 2013 (CET)<br />
*Стрелками клавиатуры поточнее подгонять объекты на нужное место.--[[Участник:Amohov|Summer Cat]] 11:26, 20 февраля 2013 (CET)<br />
*Хорошо бы добавить offline версию справки с возможностью обновления при наличии интернет подключения --[[Участник:Amohov|Summer Cat]] 07:34, 21 февраля 2013 (CET)<br />
- пока не планировал, очень быстро меняем и дополняем существующую<br />
<br />
*Сделать объект HiddenHint универсальным, щас хины 2го и 4го типа работаю только если их графика находиться на сцене с поисковыми объектами за счет этого в Travel`е в каждой сцене своя кнопка запуска хинта и индивидуальный HiddenHint, по-этому интерфейс сделан запутано. Хотелось бы один HiddenHint который отвечает за все хинты во всей игре!--[[Участник:Igood|Igood]] 08:56, 6 марта 2013 (CET)<br />
<br />
*Добавить понятие Шаблон объекта. Довольно часто мы создаём повторяющиеся структуры. Ярчайший тому пример - объект Tool(http://ge.absolutist.com/index.php/Tool), разработаный Олей. Позже, он был сделан программистами. Суть предложения:<br />
<br />
1. Программист редактора создаёт объект(машину состояний), прописывает все необходимые действия с другими объектами<br />
<br />
2. Меняет тип объекту на шаблон<br />
<br />
3. Меняет все необходимые объекты(а также, возможно и параметры используемых объектов) на переменные. (У переменной планируется 2 поля - имя в панели редактора и идентификатор). Прописывает переменным (по желанию) значения по умолчанию. Также предлагаю ввести переменную "this", которая будет обозначать обращение к самому себе.<br />
<br />
4.Переменные могут быть следующих типов:<br />
*Объект - ссылка на объект<br />
*Строка - как правило, это состояние объекта или свойство<br />
*Число - переменная численного типа.<br />
<br />
5. Создаёт новый объект, устанавливает ему тип заранее созданного шаблона. (предлагаю ввести вкладку шаблоны на равне с Global Mechanics, Global Score, Options, Social)<br />
<br />
6. Прописывает все необходимые переменные в панели объекта<br />
<br />
--[[Участник:Atonkonog|Atonkonog]] 11:34, 12 марта 2013 (CET)<br />
<br />
*При копировании объекта, подменять ссылку на самого себя. Т. е. новый объект везде должен ссылаться на себя, а не на старый объект.<br />
<br />
--[[Участник:Atonkonog|Atonkonog]] 11:34, 12 марта 2013 (CET)<br />
<br />
* Добавить полигон. Позволит получать объекты (картинки, машины и т.д.) произвольной формы, используя тайлинг и полигон. --[[Участник:Odyadina|Odyadina]] 11:58, 22 марта 2013 (CET)<br />
<br />
*Добавить cos, sin, tan, abs, sqrt, sqr - для облегчение вычисления параметров по формулам.--[[Участник:Amohov|Summer Cat]] 08:58, 16 апреля 2013 (CEST)<br />
<br />
*Добавить возможность делать объекты, которые видны только в дебаге, а при сборке не компилируются. При этом, пользующийся этим объектом программист, должен сам следить за тем, чтобы на этот объект не ссылались другие объекты.<br />
--[[Участник:Atonkonog|Atonkonog]] 17:56, 30 апреля 2013 (CEST)<br />
<br />
== Баги ==<br />
<br />
* В машине, которая загружается одновременно с загрузкой экрана, если звук (snd) стоит в первом состоянии, то он либо воспроизводится до загрузки экрана (и то не до конца или не сначала) или не воспроизводится вообще. Сейчас это обходится дополнительным предварительным состоянием с вэйтом на 400ms (не меньше!).<br />
[[Файл:Sndinit.jpg]]<br />
<br />
<br />
<br clear="all" /><br />
<br />
Баг это или не баг - считать вам. Но эта проблема отняла у меня уйму времени.<br />
Если у объекта свойство vis=0, то когда ему set-ом меняем состояние, никакие действия не выполняются и никаких предупреждений не выдаётся.<br />
<br />
Выходов из данной ситуации вижу 2:<br />
<br />
1. Обрабатывать переходы в новое состояние в невидимом объекте.<br />
<br />
2. Выдавать Warning в системной строке приложения и делать соответственную запись в лог-файл.<br />
<br />
* Добавить ползунок, для того, чтобы можно было видеть название объектов в дереве сцены. <br />
[[Файл:Дерево.JPG]]<br />
<br clear="all" /><br />
<br />
судя по описанию - писал Андрей--[[Участник:Boyarin|Boyarin]] 20:04, 3 марта 2013 (CET)<br />
<br />
*При форматировании текста в горизонтальном форматировании в подсказке есть что текст можно установить по центру, по правому краю, а вот что по левому можно я догадался только интуитивно. Прошу дополнить всплывающую подсказку.<br />
[[Файл:Text h align.jpg]]<br />
<br clear="all" /><br />
--[[Участник:Amohov|Summer Cat]] 10:13, 14 марта 2013 (CET)<br />
<br />
== Реализовано ==<br />
* Редактор ресурсов. При загрузке картинок в редактор ресурсов, хотелось бы иметь возможность видеть превью картинок.<br />
[[Файл:Редактор ресурсов.JPG|120px]]<br />
[[Файл:Предпросмотр.JPG|120px|]]<br />
<br />
* Переместив картинку из редактора ресурсов на сцену, в свойствах она имеет по умолчанию тип '''image'''. Меняя тип '''image''' на '''machine''' иконка в дереве остается по-прежнему '''image''' до первого клика. Необходимо сделать мгновенную смену иконки в дереве. <br clear="all" /><br />
<br><br />
[[Файл:Машина.JPG ]]<br />
<br />
* В редакторе ресурсов у левой половинки (в которой дерево папок) нет возможности регулировать ширину --[[Участник:Podkor|Podkor]] 16:53, 25 января 2013 (CET)<br />
[[Файл:ArtSource.jpg|300px]]<br />
<br />
* При вызове состояний в viewer нет возможности просмотреть все состояния если они не помещаются в экран. Здорово было бы иметь возможность прокручивать список<br />
[[Файл:State.jpg|200px]] <br />
--[[Участник:Podkor|Podkor]] 13:42, 19 февраля 2013 (CET)<br />
<br>''Зачем нам так много просматривать не нужных машин? Лучше сделать Debug систему где мы выберем только те машины которые хотим отследить. Желательно отслеживать состояния машин, различные параметры + было бы не плохо ставить break например когда объект перейдет в какое то состояние ставить движок на паузу!''--[[Участник:Igood|Igood]] 09:05, 20 февраля 2013 (CET)</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9A%D0%BD%D0%B8%D0%B3%D0%B0_%D0%B6%D0%B0%D0%BB%D0%BE%D0%B1_%D0%B8_%D0%BF%D0%BE%D0%B6%D0%B5%D0%BB%D0%B0%D0%BD%D0%B8%D0%B9&diff=3821Книга жалоб и пожеланий2013-04-30T15:56:17Z<p>Atonkonog: /* Новые объекты и свойства */</p>
<hr />
<div>Внимание !!<br />
* Перед публикацией внимательно читать ВСЕ!<br />
* Делаем при обсуждении отступы (двоеточие) и подписываемся (4 тильды).<br />
<br />
== Улучшение интерфейса ==<br />
<br />
* Возможность копирования состояний из машины в машину.--[[Участник:Oilich|Oilich]] 13:36, 24 января 2013 (CET)<br />
* Поворачивать, масштабировать объекты прямо на сцене (как в любом граф.редакторе) [[Участник:Steps|Steps]] 14:11, 24 января 2013 (CET)<br />
* Добавить горячие клавиши в состоянии машин. В выбранном состоянии машины, например если нажать "w" создается ф-я wait, "i"=if,<br> "m" = move, "s" = set ну и так далее. --[[Участник:Igood|Igood]] 16:10, 24 января 2013 (CET)<br />
:: С какой клавишей использовать CTRL +S сохранение + давайте уже весь список хоткеев. Проще разнести и реализовать.\<br />
<br />
* Возможность копирования ф-й(set,wait...) из одного состояния машины в другую.--[[Участник:Igood|Igood]] 16:12, 24 января 2013 (CET)<br />
:: В чем отличие от "Возможность копирования состояний из машины в машину.--[[Участник:Oilich|Oilich]] 13:36, 24 января 2013 (CET)"<br />
::: В том что это не состояния а отдельные функции в состоянии.--[[Участник:Igood|Igood]] 08:53, 25 января 2013 (CET)<br />
:::: я поддерживаю. мелочь, а приятно. [[Участник:Steps|Steps]] 12:13, 25 января 2013 (CET)<br />
<br />
* Добавить событие кнопке, изм. состояния объекта если на нее нажали в состоянии disable.--[[Участник:Igood|Igood]] 16:18, 24 января 2013 (CET)<br />
<br />
:: С точки зрения кнопки - Она "Кнопка" имеет два состояния, в состоянии disable кнопка не должна вообще воспринимать кликов. Но если всех это не запутает и нужно для космического корабля то ОК--[[Участник:Boyarin|Boyarin]] 21:45, 24 января 2013 (CET)<br />
:: Стоит обсудить. Действительно, не очень логично считать дизейбл рабочим состоянием. [[Участник:Steps|Steps]] 12:16, 25 января 2013 (CET)<br />
<br />
* Добавить возможность открывать несколько машин состояний одновременно. Сделать так, чтоб их можно было сворачивать.--[[Участник:Fhod|Fhod]] 17:00, 25 января 2013 (CET)<br />
<br />
<br />
* По логике в списке сначала должен идти параметр, а потом его значение.--[[Участник:Avereskun|Avereskun]] 10:06, 25 января 2013 (CET)<br />
<br />
[[Файл:Editor123.jpg]]<br />
<br />
* В редакторе сцен, если закрыл окно с параметрами или деревом объектов, то его можно вернуть только переоткрыв редактор. Необходимо добавить управление отображением этих окон из меню. --[[Участник:Shejko|Shejko]] 09:22, 29 января 2013 (CET) <br />
: Ну не совсем так. Правой кнопкой на панели и галкой можно включить область с деревом и проперти - Но понятно что требует в настройки вынести --[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить возможность одновременно синхронизировать и снимать синхронизацию с группы объектов.--[[Участник:Odyadina|Odyadina]] 13:54, 29 января 2013 (CET)<br />
: Согласен + можно подумать и про др груп изменения--[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить синхронизацию (да-нет) свойств сцены --[[Участник:Odyadina|Odyadina]] 10:59, 30 января 2013 (CET)<br />
: согласен--[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить возможность хранить проекты на разных дисках, не привязываясь к местонахождению редактора.<br />
Нужно с этим что-то делать:<br />
[[Файл:Файл_проекта.JPG|200px|thumb|left|описание]]<br />
<br clear="all" /><br />
--[[Участник:Dorl|Dorl]] 09:02, 31 января 2013 (CET)<br />
<br />
* Возможность добавлять графические объекты с применением к ним свойств объектов, которые уже заданы аниматором, а именно параметры кнопок, чекбоксов, НО НЕ КООРДИНАТЫ. Чтобы работало по типу пипетки--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET). <br />
<br />
Потому как часто возникает вопрос коррекции сцены с перемещением (также увеличением-уменьшением, вращением, заменой цвета и т.д.), например, тех же кнопок для улучшения общего вида сцены--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET). <br />
<br />
Во-первых - облегчит работу аниматору (не нужно будет искать новое расположение исправленного объекта), во-вторых - объект будет обладать уже заданными параметрами, в-третьих - расположение изображения будет соответствовать тому, как задумал графический дизайнер--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET).<br />
<br />
<br />
* Добавить кнопку "снять все выделения" и "выделить всё" в окно управления предзагрузкой на кнопках.<br />
<br />
[[Файл:Wind preload button.jpg|150px|thumb|left|окно в которое добавить кнопки]]<br />
<br />
<br clear="all" /><br />
--[[Участник:Shejko|Shejko]] 14:40, 13 февраля 2013 (CET)<br />
<br />
* После добавления дополнительных возможностей объекта не перемещать в начало списка параметров. Я добавляю возможность в объект в конец списка его параметров, скажем в пазл, после добавления параметра меня автоматически бросает вверх списка и чтобы поменять параметры приходится снова опускаться к добавленному параметру.<br />
<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
* Добавить кнопку "развернуть всё" в списке параметров объектов.<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
* Также в добавляемых возможностях объекта, таких как "изменить графический id", где всего 3 параметра и в любом случае для работы этого параметра необходимо заполнить все 3 поля, при добавлении возможности лучше было бы если все 3 параметра добавляются автоматически и если один из них не задал - не убирать поле после переоткрытия проекта - его всё равно придётся добавлять.<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
*Добавить для редактора текстовых ресурсов, как в редакторе ресурсов, пункт меню View с подпунктом Always on Top.Было очень актуально при работе с хиддн объектами.<br />
--[[Участник:lkunica|lkunica]] 16:40, 6 марта 2013 (CET)<br />
<br />
*Возможность поменять графический ресурс не перетаскивая его. Для этого программист редактора в поле "res" прописывает имя изображения. При этом, редактор производит поиск и подставляет первое изображение, соответствующее данному имени. Если не находит - выдаёт ошибку.<br />
--[[Участник:Atonkonog|Atonkonog]] 15:40, 18 марта 2013 (CET)<br />
** а если имен изображений несколько, что тогда? какой брать? При перетаскивании привязываем по id а не по имени. --[[Участник:Boyarin|Boyarin]] 07:29, 20 марта 2013 (CET)<br />
*если картинок несколько - берётся первая, которая будет найдена.<br />
--[[Участник:Atonkonog|Atonkonog]] 14:29, 30 апреля 2013 (CEST) <br />
<br />
*Возможность поменять текст не перетаскивая его. Для этого программист редактора в поле "" прописывает имя изображения. При этом, редактор производит поиск и подставляет первую строку, соответствующую данному имени. Если не находит - выдаёт ошибку.<br />
--[[Участник:Atonkonog|Atonkonog]] 15:40, 18 марта 2013 (CET)<br />
** а если имен текстовых объектов несколько, что тогда? ну дальше понятно .... --[[Участник:Boyarin|Boyarin]] 07:29, 20 марта 2013 (CET) <br />
<br />
*Добавить возможность быстро устанавливать следующий/предыдущий текст и графический ресурс в граф. базе ресурсов. Довольно часто бывает, что нужно, например, добавить кучу инвентарных объектов, идентификаторы которых идут последовательно один за другим<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*При копировании машин состояний:<br />
1. Копировать ссылку на самого себя (уже писал, повторяюсь)<br />
2. Если есть вложенные объекты, в новом объекте ссылки должны ссылаться на его подобъекты. Если у объектов есть подобъекты - принцип тоже должен действовать<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*Добавить множественное копирование<br />
Добавить возможность копировать объект несколько раз, при этом, предусмотреть инкрементированную замену параметров объекта(переменные локальные и глобальные, идентификаторы объектов, ресурсов, текстов)<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*Добавить возможность во viewer'e менять любой параметр и состояние любого объекта(простенький дебаг)--[[Участник:Atonkonog|Atonkonog]] 14:45, 26 марта 2013 (CET)<br />
<br />
*Добавить возможность предосмотра текста в объекте текст. Чтобы любое форматирование сразу отображалось. Надоело после каждой правки текста пересохранять весь проект, чтобы увидеть результат.--[[Участник:Amohov|Summer Cat]] 10:51, 1 апреля 2013 (CEST)<br />
<br />
*Добавить возможность менять тип объекта у группы объектов. Например на сцене есть 50 объектов и все они должны быть хидденобъектами. В текущей реализации надо у каждого объекта отдельно менять тип. --[[Участник:Shejko|Shejko]] 08:51, 3 апреля 2013 (CEST)<br />
<br />
*Добавить горячие клавиши для вызова редактора ресурсов и редактора текстов.--[[Участник:Amohov|Summer Cat]] 16:48, 11 апреля 2013 (CEST)<br />
<br />
*Сделать так, чтобы при наведении на объект выбранный в поле '''obj''', в пояснении отображался ''ID'' объекта. Такая возможность позволит избежать ошибок в случаях: <br />
:а) когда вдруг существуют два объекта с одинаковым именем; <br />
:б) когда в поле отображается ''нет'', в этом случае возможны три варианта: объект не выбран, объект с таким ID удален, объект находится на другом экране.--[[Участник:Odyadina|Odyadina]] 12:19, 18 апреля 2013 (CEST)<br />
<br />
*Вынести кнопку "Delete temp data" на панель где кнопки запуска вьювера,базы ресурсов и т.д.--[[Участник:Nbeznosov|Nbeznosov]] 09:13, 26 апреля 2013 (CEST)<br />
<br />
== Новые объекты и свойства==<br />
<br />
* Добавить сплайн (кривая линия), который можно рисовать на сцене и передавать команде move [[Участник:Steps|Steps]] 14:11, 24 января 2013 (CET)<br />
- запланировано--[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
* Добавить в редактор генератор комиксов. Хорошим и простым примером является [http://1001mem.ru/create_comics генератор комиков] Это пожелания на будущее. --[[Участник:Dorl|Dorl]] 10:35, 25 января 2013 (CET)<br />
- все равно не понял --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
* Машина состояний. Добавить в команду '''drag''' распознавания в какую сторону происходит движение (вправо, влево, вниз, вверх) при этом давать возможность менять графический ресурс в зависимости от направления. --[[Участник:Dorl|Dorl]] 16:48, 25 января 2013 (CET)<br />
[[Файл:[[Файл:Drag.JPG|200px|thumb|left|]]<br />
[[Файл:Drag_fish.JPG|200px|thumb|left|]]<br />
<br clear="all" /><br />
* Добавить гибкость работы со шрифтами. Как минимум должна быть: ''возможность наклона'', '''возможность полужирного начертания.''' --[[Участник:Dorl|Dorl]] 09:08, 31 января 2013 (CET)<br />
- покурим, но пока все упирается в лишнюю память<br />
*Когда запущен редактор ресурсов и был свёрнут, то при попытке его запустить снова с панели хорошо бы разворачивать, а не ругаться что он уже запущен.--[[Участник:Amohov|Summer Cat]] 11:00, 20 февраля 2013 (CET)<br />
- согласен--[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Будет очень удобно если вызывать меню методов двойным кликом по этой области, а не по кнопке. Экономит немного времени на разработку проекта.--[[Участник:Amohov|Summer Cat]] 11:11, 20 февраля 2013 (CET)<br />
[[Файл:New addons.PNG|200px|thumb|left|]]<br clear="all" /><br />
*Добавить возможность вызвать редактор ресурсов, когда работаешь с свойствами машины.--[[Участник:Amohov|Summer Cat]] 11:16, 20 февраля 2013 (CET)<br />
- ок --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Выделить несколько объектов и изменить например на машины сразу несколько одним кликом.--[[Участник:Amohov|Summer Cat]] 11:19, 20 февраля 2013 (CET)<br />
- ок --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Когда сильно увеличен экран проекта и мы видим только часть его, хорошо бы на колесо мышки назначить руку для передвижение по экрану, а не пользоваться полосами прокрутки. Это сильно ускорит навигацию по рабочей области а вследствие и разработку.--[[Участник:Amohov|Summer Cat]] 11:24, 20 февраля 2013 (CET)<br />
*Стрелками клавиатуры поточнее подгонять объекты на нужное место.--[[Участник:Amohov|Summer Cat]] 11:26, 20 февраля 2013 (CET)<br />
*Хорошо бы добавить offline версию справки с возможностью обновления при наличии интернет подключения --[[Участник:Amohov|Summer Cat]] 07:34, 21 февраля 2013 (CET)<br />
- пока не планировал, очень быстро меняем и дополняем существующую<br />
<br />
*Сделать объект HiddenHint универсальным, щас хины 2го и 4го типа работаю только если их графика находиться на сцене с поисковыми объектами за счет этого в Travel`е в каждой сцене своя кнопка запуска хинта и индивидуальный HiddenHint, по-этому интерфейс сделан запутано. Хотелось бы один HiddenHint который отвечает за все хинты во всей игре!--[[Участник:Igood|Igood]] 08:56, 6 марта 2013 (CET)<br />
<br />
*Добавить понятие Шаблон объекта. Довольно часто мы создаём повторяющиеся структуры. Ярчайший тому пример - объект Tool(http://ge.absolutist.com/index.php/Tool), разработаный Олей. Позже, он был сделан программистами. Суть предложения:<br />
<br />
1. Программист редактора создаёт объект(машину состояний), прописывает все необходимые действия с другими объектами<br />
<br />
2. Меняет тип объекту на шаблон<br />
<br />
3. Меняет все необходимые объекты(а также, возможно и параметры используемых объектов) на переменные. (У переменной планируется 2 поля - имя в панели редактора и идентификатор). Прописывает переменным (по желанию) значения по умолчанию. Также предлагаю ввести переменную "this", которая будет обозначать обращение к самому себе.<br />
<br />
4.Переменные могут быть следующих типов:<br />
*Объект - ссылка на объект<br />
*Строка - как правило, это состояние объекта или свойство<br />
*Число - переменная численного типа.<br />
<br />
5. Создаёт новый объект, устанавливает ему тип заранее созданного шаблона. (предлагаю ввести вкладку шаблоны на равне с Global Mechanics, Global Score, Options, Social)<br />
<br />
6. Прописывает все необходимые переменные в панели объекта<br />
<br />
--[[Участник:Atonkonog|Atonkonog]] 11:34, 12 марта 2013 (CET)<br />
<br />
*При копировании объекта, подменять ссылку на самого себя. Т. е. новый объект везде должен ссылаться на себя, а не на старый объект.<br />
<br />
--[[Участник:Atonkonog|Atonkonog]] 11:34, 12 марта 2013 (CET)<br />
<br />
* Добавить полигон. Позволит получать объекты (картинки, машины и т.д.) произвольной формы, используя тайлинг и полигон. --[[Участник:Odyadina|Odyadina]] 11:58, 22 марта 2013 (CET)<br />
<br />
*Добавить cos, sin, tan, abs, sqrt, sqr - для облегчение вычисления параметров по формулам.--[[Участник:Amohov|Summer Cat]] 08:58, 16 апреля 2013 (CEST)<br />
<br />
*Добавить возможность делать объекты, которые видны только в дебаге, а при сборке не компилируются. При этом, пользующийся этим объектом программист, должен сам следить за тем, чтобы на этот объект не ссылались другие объекты.<br />
<br />
== Баги ==<br />
<br />
* В машине, которая загружается одновременно с загрузкой экрана, если звук (snd) стоит в первом состоянии, то он либо воспроизводится до загрузки экрана (и то не до конца или не сначала) или не воспроизводится вообще. Сейчас это обходится дополнительным предварительным состоянием с вэйтом на 400ms (не меньше!).<br />
[[Файл:Sndinit.jpg]]<br />
<br />
<br />
<br clear="all" /><br />
<br />
Баг это или не баг - считать вам. Но эта проблема отняла у меня уйму времени.<br />
Если у объекта свойство vis=0, то когда ему set-ом меняем состояние, никакие действия не выполняются и никаких предупреждений не выдаётся.<br />
<br />
Выходов из данной ситуации вижу 2:<br />
<br />
1. Обрабатывать переходы в новое состояние в невидимом объекте.<br />
<br />
2. Выдавать Warning в системной строке приложения и делать соответственную запись в лог-файл.<br />
<br />
* Добавить ползунок, для того, чтобы можно было видеть название объектов в дереве сцены. <br />
[[Файл:Дерево.JPG]]<br />
<br clear="all" /><br />
<br />
судя по описанию - писал Андрей--[[Участник:Boyarin|Boyarin]] 20:04, 3 марта 2013 (CET)<br />
<br />
*При форматировании текста в горизонтальном форматировании в подсказке есть что текст можно установить по центру, по правому краю, а вот что по левому можно я догадался только интуитивно. Прошу дополнить всплывающую подсказку.<br />
[[Файл:Text h align.jpg]]<br />
<br clear="all" /><br />
--[[Участник:Amohov|Summer Cat]] 10:13, 14 марта 2013 (CET)<br />
<br />
== Реализовано ==<br />
* Редактор ресурсов. При загрузке картинок в редактор ресурсов, хотелось бы иметь возможность видеть превью картинок.<br />
[[Файл:Редактор ресурсов.JPG|120px]]<br />
[[Файл:Предпросмотр.JPG|120px|]]<br />
<br />
* Переместив картинку из редактора ресурсов на сцену, в свойствах она имеет по умолчанию тип '''image'''. Меняя тип '''image''' на '''machine''' иконка в дереве остается по-прежнему '''image''' до первого клика. Необходимо сделать мгновенную смену иконки в дереве. <br clear="all" /><br />
<br><br />
[[Файл:Машина.JPG ]]<br />
<br />
* В редакторе ресурсов у левой половинки (в которой дерево папок) нет возможности регулировать ширину --[[Участник:Podkor|Podkor]] 16:53, 25 января 2013 (CET)<br />
[[Файл:ArtSource.jpg|300px]]<br />
<br />
* При вызове состояний в viewer нет возможности просмотреть все состояния если они не помещаются в экран. Здорово было бы иметь возможность прокручивать список<br />
[[Файл:State.jpg|200px]] <br />
--[[Участник:Podkor|Podkor]] 13:42, 19 февраля 2013 (CET)<br />
<br>''Зачем нам так много просматривать не нужных машин? Лучше сделать Debug систему где мы выберем только те машины которые хотим отследить. Желательно отслеживать состояния машин, различные параметры + было бы не плохо ставить break например когда объект перейдет в какое то состояние ставить движок на паузу!''--[[Участник:Igood|Igood]] 09:05, 20 февраля 2013 (CET)</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=%D0%9A%D0%BD%D0%B8%D0%B3%D0%B0_%D0%B6%D0%B0%D0%BB%D0%BE%D0%B1_%D0%B8_%D0%BF%D0%BE%D0%B6%D0%B5%D0%BB%D0%B0%D0%BD%D0%B8%D0%B9&diff=3818Книга жалоб и пожеланий2013-04-30T12:29:16Z<p>Atonkonog: /* Улучшение интерфейса */</p>
<hr />
<div>Внимание !!<br />
* Перед публикацией внимательно читать ВСЕ!<br />
* Делаем при обсуждении отступы (двоеточие) и подписываемся (4 тильды).<br />
<br />
== Улучшение интерфейса ==<br />
<br />
* Возможность копирования состояний из машины в машину.--[[Участник:Oilich|Oilich]] 13:36, 24 января 2013 (CET)<br />
* Поворачивать, масштабировать объекты прямо на сцене (как в любом граф.редакторе) [[Участник:Steps|Steps]] 14:11, 24 января 2013 (CET)<br />
* Добавить горячие клавиши в состоянии машин. В выбранном состоянии машины, например если нажать "w" создается ф-я wait, "i"=if,<br> "m" = move, "s" = set ну и так далее. --[[Участник:Igood|Igood]] 16:10, 24 января 2013 (CET)<br />
:: С какой клавишей использовать CTRL +S сохранение + давайте уже весь список хоткеев. Проще разнести и реализовать.\<br />
<br />
* Возможность копирования ф-й(set,wait...) из одного состояния машины в другую.--[[Участник:Igood|Igood]] 16:12, 24 января 2013 (CET)<br />
:: В чем отличие от "Возможность копирования состояний из машины в машину.--[[Участник:Oilich|Oilich]] 13:36, 24 января 2013 (CET)"<br />
::: В том что это не состояния а отдельные функции в состоянии.--[[Участник:Igood|Igood]] 08:53, 25 января 2013 (CET)<br />
:::: я поддерживаю. мелочь, а приятно. [[Участник:Steps|Steps]] 12:13, 25 января 2013 (CET)<br />
<br />
* Добавить событие кнопке, изм. состояния объекта если на нее нажали в состоянии disable.--[[Участник:Igood|Igood]] 16:18, 24 января 2013 (CET)<br />
<br />
:: С точки зрения кнопки - Она "Кнопка" имеет два состояния, в состоянии disable кнопка не должна вообще воспринимать кликов. Но если всех это не запутает и нужно для космического корабля то ОК--[[Участник:Boyarin|Boyarin]] 21:45, 24 января 2013 (CET)<br />
:: Стоит обсудить. Действительно, не очень логично считать дизейбл рабочим состоянием. [[Участник:Steps|Steps]] 12:16, 25 января 2013 (CET)<br />
<br />
* Добавить возможность открывать несколько машин состояний одновременно. Сделать так, чтоб их можно было сворачивать.--[[Участник:Fhod|Fhod]] 17:00, 25 января 2013 (CET)<br />
<br />
<br />
* По логике в списке сначала должен идти параметр, а потом его значение.--[[Участник:Avereskun|Avereskun]] 10:06, 25 января 2013 (CET)<br />
<br />
[[Файл:Editor123.jpg]]<br />
<br />
* В редакторе сцен, если закрыл окно с параметрами или деревом объектов, то его можно вернуть только переоткрыв редактор. Необходимо добавить управление отображением этих окон из меню. --[[Участник:Shejko|Shejko]] 09:22, 29 января 2013 (CET) <br />
: Ну не совсем так. Правой кнопкой на панели и галкой можно включить область с деревом и проперти - Но понятно что требует в настройки вынести --[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить возможность одновременно синхронизировать и снимать синхронизацию с группы объектов.--[[Участник:Odyadina|Odyadina]] 13:54, 29 января 2013 (CET)<br />
: Согласен + можно подумать и про др груп изменения--[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить синхронизацию (да-нет) свойств сцены --[[Участник:Odyadina|Odyadina]] 10:59, 30 января 2013 (CET)<br />
: согласен--[[Участник:Boyarin|Boyarin]] 21:29, 30 января 2013 (CET)<br />
<br />
* Добавить возможность хранить проекты на разных дисках, не привязываясь к местонахождению редактора.<br />
Нужно с этим что-то делать:<br />
[[Файл:Файл_проекта.JPG|200px|thumb|left|описание]]<br />
<br clear="all" /><br />
--[[Участник:Dorl|Dorl]] 09:02, 31 января 2013 (CET)<br />
<br />
* Возможность добавлять графические объекты с применением к ним свойств объектов, которые уже заданы аниматором, а именно параметры кнопок, чекбоксов, НО НЕ КООРДИНАТЫ. Чтобы работало по типу пипетки--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET). <br />
<br />
Потому как часто возникает вопрос коррекции сцены с перемещением (также увеличением-уменьшением, вращением, заменой цвета и т.д.), например, тех же кнопок для улучшения общего вида сцены--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET). <br />
<br />
Во-первых - облегчит работу аниматору (не нужно будет искать новое расположение исправленного объекта), во-вторых - объект будет обладать уже заданными параметрами, в-третьих - расположение изображения будет соответствовать тому, как задумал графический дизайнер--[[Участник:Lsokol|Lsokol]] 13:17, 6 февраля 2013 (CET).<br />
<br />
<br />
* Добавить кнопку "снять все выделения" и "выделить всё" в окно управления предзагрузкой на кнопках.<br />
<br />
[[Файл:Wind preload button.jpg|150px|thumb|left|окно в которое добавить кнопки]]<br />
<br />
<br clear="all" /><br />
--[[Участник:Shejko|Shejko]] 14:40, 13 февраля 2013 (CET)<br />
<br />
* После добавления дополнительных возможностей объекта не перемещать в начало списка параметров. Я добавляю возможность в объект в конец списка его параметров, скажем в пазл, после добавления параметра меня автоматически бросает вверх списка и чтобы поменять параметры приходится снова опускаться к добавленному параметру.<br />
<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
* Добавить кнопку "развернуть всё" в списке параметров объектов.<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
* Также в добавляемых возможностях объекта, таких как "изменить графический id", где всего 3 параметра и в любом случае для работы этого параметра необходимо заполнить все 3 поля, при добавлении возможности лучше было бы если все 3 параметра добавляются автоматически и если один из них не задал - не убирать поле после переоткрытия проекта - его всё равно придётся добавлять.<br />
--[[Участник:Shejko|Shejko]] 09:38, 14 февраля 2013 (CET)<br />
<br />
*Добавить для редактора текстовых ресурсов, как в редакторе ресурсов, пункт меню View с подпунктом Always on Top.Было очень актуально при работе с хиддн объектами.<br />
--[[Участник:lkunica|lkunica]] 16:40, 6 марта 2013 (CET)<br />
<br />
*Возможность поменять графический ресурс не перетаскивая его. Для этого программист редактора в поле "res" прописывает имя изображения. При этом, редактор производит поиск и подставляет первое изображение, соответствующее данному имени. Если не находит - выдаёт ошибку.<br />
--[[Участник:Atonkonog|Atonkonog]] 15:40, 18 марта 2013 (CET)<br />
** а если имен изображений несколько, что тогда? какой брать? При перетаскивании привязываем по id а не по имени. --[[Участник:Boyarin|Boyarin]] 07:29, 20 марта 2013 (CET)<br />
*если картинок несколько - берётся первая, которая будет найдена.<br />
--[[Участник:Atonkonog|Atonkonog]] 14:29, 30 апреля 2013 (CEST) <br />
<br />
*Возможность поменять текст не перетаскивая его. Для этого программист редактора в поле "" прописывает имя изображения. При этом, редактор производит поиск и подставляет первую строку, соответствующую данному имени. Если не находит - выдаёт ошибку.<br />
--[[Участник:Atonkonog|Atonkonog]] 15:40, 18 марта 2013 (CET)<br />
** а если имен текстовых объектов несколько, что тогда? ну дальше понятно .... --[[Участник:Boyarin|Boyarin]] 07:29, 20 марта 2013 (CET) <br />
<br />
*Добавить возможность быстро устанавливать следующий/предыдущий текст и графический ресурс в граф. базе ресурсов. Довольно часто бывает, что нужно, например, добавить кучу инвентарных объектов, идентификаторы которых идут последовательно один за другим<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*При копировании машин состояний:<br />
1. Копировать ссылку на самого себя (уже писал, повторяюсь)<br />
2. Если есть вложенные объекты, в новом объекте ссылки должны ссылаться на его подобъекты. Если у объектов есть подобъекты - принцип тоже должен действовать<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*Добавить множественное копирование<br />
Добавить возможность копировать объект несколько раз, при этом, предусмотреть инкрементированную замену параметров объекта(переменные локальные и глобальные, идентификаторы объектов, ресурсов, текстов)<br />
--[[Участник:Atonkonog|Atonkonog]] 16:46, 18 марта 2013 (CET)<br />
<br />
*Добавить возможность во viewer'e менять любой параметр и состояние любого объекта(простенький дебаг)--[[Участник:Atonkonog|Atonkonog]] 14:45, 26 марта 2013 (CET)<br />
<br />
*Добавить возможность предосмотра текста в объекте текст. Чтобы любое форматирование сразу отображалось. Надоело после каждой правки текста пересохранять весь проект, чтобы увидеть результат.--[[Участник:Amohov|Summer Cat]] 10:51, 1 апреля 2013 (CEST)<br />
<br />
*Добавить возможность менять тип объекта у группы объектов. Например на сцене есть 50 объектов и все они должны быть хидденобъектами. В текущей реализации надо у каждого объекта отдельно менять тип. --[[Участник:Shejko|Shejko]] 08:51, 3 апреля 2013 (CEST)<br />
<br />
*Добавить горячие клавиши для вызова редактора ресурсов и редактора текстов.--[[Участник:Amohov|Summer Cat]] 16:48, 11 апреля 2013 (CEST)<br />
<br />
*Сделать так, чтобы при наведении на объект выбранный в поле '''obj''', в пояснении отображался ''ID'' объекта. Такая возможность позволит избежать ошибок в случаях: <br />
:а) когда вдруг существуют два объекта с одинаковым именем; <br />
:б) когда в поле отображается ''нет'', в этом случае возможны три варианта: объект не выбран, объект с таким ID удален, объект находится на другом экране.--[[Участник:Odyadina|Odyadina]] 12:19, 18 апреля 2013 (CEST)<br />
<br />
*Вынести кнопку "Delete temp data" на панель где кнопки запуска вьювера,базы ресурсов и т.д.--[[Участник:Nbeznosov|Nbeznosov]] 09:13, 26 апреля 2013 (CEST)<br />
<br />
== Новые объекты и свойства==<br />
<br />
* Добавить сплайн (кривая линия), который можно рисовать на сцене и передавать команде move [[Участник:Steps|Steps]] 14:11, 24 января 2013 (CET)<br />
- запланировано--[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
* Добавить в редактор генератор комиксов. Хорошим и простым примером является [http://1001mem.ru/create_comics генератор комиков] Это пожелания на будущее. --[[Участник:Dorl|Dorl]] 10:35, 25 января 2013 (CET)<br />
- все равно не понял --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
* Машина состояний. Добавить в команду '''drag''' распознавания в какую сторону происходит движение (вправо, влево, вниз, вверх) при этом давать возможность менять графический ресурс в зависимости от направления. --[[Участник:Dorl|Dorl]] 16:48, 25 января 2013 (CET)<br />
[[Файл:[[Файл:Drag.JPG|200px|thumb|left|]]<br />
[[Файл:Drag_fish.JPG|200px|thumb|left|]]<br />
<br clear="all" /><br />
* Добавить гибкость работы со шрифтами. Как минимум должна быть: ''возможность наклона'', '''возможность полужирного начертания.''' --[[Участник:Dorl|Dorl]] 09:08, 31 января 2013 (CET)<br />
- покурим, но пока все упирается в лишнюю память<br />
*Когда запущен редактор ресурсов и был свёрнут, то при попытке его запустить снова с панели хорошо бы разворачивать, а не ругаться что он уже запущен.--[[Участник:Amohov|Summer Cat]] 11:00, 20 февраля 2013 (CET)<br />
- согласен--[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Будет очень удобно если вызывать меню методов двойным кликом по этой области, а не по кнопке. Экономит немного времени на разработку проекта.--[[Участник:Amohov|Summer Cat]] 11:11, 20 февраля 2013 (CET)<br />
[[Файл:New addons.PNG|200px|thumb|left|]]<br clear="all" /><br />
*Добавить возможность вызвать редактор ресурсов, когда работаешь с свойствами машины.--[[Участник:Amohov|Summer Cat]] 11:16, 20 февраля 2013 (CET)<br />
- ок --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Выделить несколько объектов и изменить например на машины сразу несколько одним кликом.--[[Участник:Amohov|Summer Cat]] 11:19, 20 февраля 2013 (CET)<br />
- ок --[[Участник:Boyarin|Boyarin]] 20:10, 3 марта 2013 (CET)<br />
*Когда сильно увеличен экран проекта и мы видим только часть его, хорошо бы на колесо мышки назначить руку для передвижение по экрану, а не пользоваться полосами прокрутки. Это сильно ускорит навигацию по рабочей области а вследствие и разработку.--[[Участник:Amohov|Summer Cat]] 11:24, 20 февраля 2013 (CET)<br />
*Стрелками клавиатуры поточнее подгонять объекты на нужное место.--[[Участник:Amohov|Summer Cat]] 11:26, 20 февраля 2013 (CET)<br />
*Хорошо бы добавить offline версию справки с возможностью обновления при наличии интернет подключения --[[Участник:Amohov|Summer Cat]] 07:34, 21 февраля 2013 (CET)<br />
- пока не планировал, очень быстро меняем и дополняем существующую<br />
<br />
*Сделать объект HiddenHint универсальным, щас хины 2го и 4го типа работаю только если их графика находиться на сцене с поисковыми объектами за счет этого в Travel`е в каждой сцене своя кнопка запуска хинта и индивидуальный HiddenHint, по-этому интерфейс сделан запутано. Хотелось бы один HiddenHint который отвечает за все хинты во всей игре!--[[Участник:Igood|Igood]] 08:56, 6 марта 2013 (CET)<br />
<br />
*Добавить понятие Шаблон объекта. Довольно часто мы создаём повторяющиеся структуры. Ярчайший тому пример - объект Tool(http://ge.absolutist.com/index.php/Tool), разработаный Олей. Позже, он был сделан программистами. Суть предложения:<br />
<br />
1. Программист редактора создаёт объект(машину состояний), прописывает все необходимые действия с другими объектами<br />
<br />
2. Меняет тип объекту на шаблон<br />
<br />
3. Меняет все необходимые объекты(а также, возможно и параметры используемых объектов) на переменные. (У переменной планируется 2 поля - имя в панели редактора и идентификатор). Прописывает переменным (по желанию) значения по умолчанию. Также предлагаю ввести переменную "this", которая будет обозначать обращение к самому себе.<br />
<br />
4.Переменные могут быть следующих типов:<br />
*Объект - ссылка на объект<br />
*Строка - как правило, это состояние объекта или свойство<br />
*Число - переменная численного типа.<br />
<br />
5. Создаёт новый объект, устанавливает ему тип заранее созданного шаблона. (предлагаю ввести вкладку шаблоны на равне с Global Mechanics, Global Score, Options, Social)<br />
<br />
6. Прописывает все необходимые переменные в панели объекта<br />
<br />
--[[Участник:Atonkonog|Atonkonog]] 11:34, 12 марта 2013 (CET)<br />
<br />
*При копировании объекта, подменять ссылку на самого себя. Т. е. новый объект везде должен ссылаться на себя, а не на старый объект.<br />
<br />
--[[Участник:Atonkonog|Atonkonog]] 11:34, 12 марта 2013 (CET)<br />
<br />
* Добавить полигон. Позволит получать объекты (картинки, машины и т.д.) произвольной формы, используя тайлинг и полигон. --[[Участник:Odyadina|Odyadina]] 11:58, 22 марта 2013 (CET)<br />
<br />
*Добавить cos, sin, tan, abs, sqrt, sqr - для облегчение вычисления параметров по формулам.--[[Участник:Amohov|Summer Cat]] 08:58, 16 апреля 2013 (CEST)<br />
<br />
== Баги ==<br />
<br />
* В машине, которая загружается одновременно с загрузкой экрана, если звук (snd) стоит в первом состоянии, то он либо воспроизводится до загрузки экрана (и то не до конца или не сначала) или не воспроизводится вообще. Сейчас это обходится дополнительным предварительным состоянием с вэйтом на 400ms (не меньше!).<br />
[[Файл:Sndinit.jpg]]<br />
<br />
<br />
<br clear="all" /><br />
<br />
Баг это или не баг - считать вам. Но эта проблема отняла у меня уйму времени.<br />
Если у объекта свойство vis=0, то когда ему set-ом меняем состояние, никакие действия не выполняются и никаких предупреждений не выдаётся.<br />
<br />
Выходов из данной ситуации вижу 2:<br />
<br />
1. Обрабатывать переходы в новое состояние в невидимом объекте.<br />
<br />
2. Выдавать Warning в системной строке приложения и делать соответственную запись в лог-файл.<br />
<br />
* Добавить ползунок, для того, чтобы можно было видеть название объектов в дереве сцены. <br />
[[Файл:Дерево.JPG]]<br />
<br clear="all" /><br />
<br />
судя по описанию - писал Андрей--[[Участник:Boyarin|Boyarin]] 20:04, 3 марта 2013 (CET)<br />
<br />
*При форматировании текста в горизонтальном форматировании в подсказке есть что текст можно установить по центру, по правому краю, а вот что по левому можно я догадался только интуитивно. Прошу дополнить всплывающую подсказку.<br />
[[Файл:Text h align.jpg]]<br />
<br clear="all" /><br />
--[[Участник:Amohov|Summer Cat]] 10:13, 14 марта 2013 (CET)<br />
<br />
== Реализовано ==<br />
* Редактор ресурсов. При загрузке картинок в редактор ресурсов, хотелось бы иметь возможность видеть превью картинок.<br />
[[Файл:Редактор ресурсов.JPG|120px]]<br />
[[Файл:Предпросмотр.JPG|120px|]]<br />
<br />
* Переместив картинку из редактора ресурсов на сцену, в свойствах она имеет по умолчанию тип '''image'''. Меняя тип '''image''' на '''machine''' иконка в дереве остается по-прежнему '''image''' до первого клика. Необходимо сделать мгновенную смену иконки в дереве. <br clear="all" /><br />
<br><br />
[[Файл:Машина.JPG ]]<br />
<br />
* В редакторе ресурсов у левой половинки (в которой дерево папок) нет возможности регулировать ширину --[[Участник:Podkor|Podkor]] 16:53, 25 января 2013 (CET)<br />
[[Файл:ArtSource.jpg|300px]]<br />
<br />
* При вызове состояний в viewer нет возможности просмотреть все состояния если они не помещаются в экран. Здорово было бы иметь возможность прокручивать список<br />
[[Файл:State.jpg|200px]] <br />
--[[Участник:Podkor|Podkor]] 13:42, 19 февраля 2013 (CET)<br />
<br>''Зачем нам так много просматривать не нужных машин? Лучше сделать Debug систему где мы выберем только те машины которые хотим отследить. Желательно отслеживать состояния машин, различные параметры + было бы не плохо ставить break например когда объект перейдет в какое то состояние ставить движок на паузу!''--[[Участник:Igood|Igood]] 09:05, 20 февраля 2013 (CET)</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=3817Machine2013-04-30T10:20:26Z<p>Atonkonog: /* Достоинства и недостатки */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение.<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается обычным переводом в состояние, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=3816Machine2013-04-30T10:19:37Z<p>Atonkonog: /* Краткое описание алгоритма */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение.<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
<br />
3. Отбрасывается целая часть а<br />
<br />
4. Запись результата во внутренню переменную val<br />
<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается в 1 состоянии, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=3815Machine2013-04-30T08:56:13Z<p>Atonkonog: /* Random-псевдо */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение.<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
3. Отбрасывается целая часть а<br />
4. Запись результата во внутренню переменную val<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества вполне достаточно.<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: результат достигается в 1 состоянии, без применения итераций, благодаря этому, к данному генератору случайных чисел может иметь доступ неограниченное число объектов.<br />
<br />
Недостатки: (они уже описаны выше) малое количество выдаваемых значений, цикличность последовательности.</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=3814Machine2013-04-30T08:50:48Z<p>Atonkonog: /* Random-псевдо */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение.<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле:<br />
<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
<br />
<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
1. Устанавливается начальное значение индекса index=101 (экспериментальное)<br />
2. Подсчитывается значение а= index*10000/(index+1)<br />
3. Отбрасывается целая часть а<br />
4. Запись результата во внутренню переменную val<br />
5. Если индекс стал больше 200- ставим его снова 101.<br />
<br />
=== Как пользоваться? ===<br />
1. Переводим объект random_pseudo в состояние count<br />
2. Считываем результат из переменной val<br />
<br />
=== Какие могут возникнуть проблемы? ===<br />
Проблема, собственно, только одна - бедность данного генератора, т. к. он имеет всего 100 различных значений. Однако, для производства игр, такого количества достаточно.</div>Atonkonoghttps://wiki.appsalutecreator.com/index.php?title=Machine&diff=3813Machine2013-04-30T08:48:07Z<p>Atonkonog: /* Достоинства и недостатки */</p>
<hr />
<div>{{TOC right}}<br />
'''Машина состояний''' (state machine) позволяет описывать сложное поведение игровых объектов. Для машин с типовым набором состояний и поведений вводятся отдельные типы объектов. Например, кнопка, по своей сути, является машиной состояний.<br />
<br />
== Введение ==<br />
<br />
Логика поведения машины разбивается на отдельные узлы (состояния). Машина всегда находится строго в одном состоянии. Переход из одного состояния в другое происходит либо в результате внешнего воздействия на машину, либо в результате окончания некоторых процессов протекающих внутри неё<br />
<br />
Любая машина состояний может быть изображена в виде графа с кружочками и стрелками. У машины всегда активно строго одно состояние (ниже это изображено на левом рисунке темным кружком):<br />
<center><br />
[[Файл:def_states.png]]<br />
</center><br />
Машина состояний не обладает памятью. Это означает, что для анализа того, что произойдет в данном состоянии, неважно как мы в него попали, и какова была предыстория переходов. Важно, только, что мы находимся в этом состоянии. Такое отсутствие памяти упрощает анализ логики машины, так как каждый раз мы концентрируемся на одном конкретном состоянии, а всю логику работы разбиваем на отдельные кирпичики-состояния.<br />
<br />
Выше на правом рисунке изображено некоторое состояние. При входе в него, происходит инициализация состояния. Если на объект оказываются внешние воздействия, то он может покинуть состояние. Наконец, внутри состояния могут работать различные процессы.<br />
<br />
Все команды состояния, разбиваются на три группы:<br />
* '''[[#Инициализация|Инициализация]]''':<br />
** '''[[#draw|draw]]''' - установка графического ресурса;<br />
** '''[[#init|init]]''' - инициализация параметров машины (координаты и т.п.);<br />
** '''[[#set|set]]''' - установка состояния другого объекта;<br />
** '''[[#play|play]]''' - проиграть звук;<br />
** '''[[#var|var]]''' - переменная, которой присваивается значение параметра объекта;<br />
** '''[[#buy|buy]]''' - запуск процедуры in-app покупки.<br />
* '''[[#Процессы|Процессы]]''':<br />
** '''[[#wait|wait]]''' - задержка по времени;<br />
** '''[[#move|move]]''' - равномерное движение;<br />
** '''[[#rot|rot]]''' - вращение вокруг точки пивота;<br />
** '''[[#alpha|alpha]]''' - изменение прозрачности;<br />
** '''[[#scale|scale]]''' - изменение размера;<br />
** '''[[#phys|phys]]''' - ускоренное движение.<br />
* '''[[#Воздействия|Воздействия]]''':<br />
** '''[[#click|click]]''' - что делать при клике на машине;<br />
** '''[[#drop|drop]]''' - на машине отпущена клавиша мыши;<br />
** '''[[#drag|drag]]''' - машину схватили и тащат;<br />
** '''[[#throw|throw]]''' - машину схватили и кинули;<br />
** '''[[#apply|apply]]''' - сработает при пересечении машины с линией или объектом;<br />
** '''[[#touch_in|touch_in]]''' - наведение мыши/пальца на машину, если палец "тащат" по экрану;<br />
** '''[[#touch_out|touch_out]]''' - выведение мыши из машины, если палец "тащат" по экрану;<br />
** '''[[#mouse_in|mouse_in]]''' - наведение мыши на машину даже если не нажата кнопка мыши;<br />
** '''[[#mouse_out|mouse_out]]''' - выведение мыши из машины даже если не нажата кнопка мыши.<br />
<br />
Кроме этого, есть команда '''[[#if|if]]''', вызываемая другими командами. В ней описываются некоторые логические условия, выполнение которых говорит команде (которая вызвала этот '''if'''), что можно завершать работу. Для разных команд использование этого параметра несколько '''отличается'''!<br />
<br />
Начальные понятия и методы работы с машинами состояний находятся в [[Learning|уроках]],<br />
начиная с [[Checkbox как машина состояний|третьего]].<br />
<br />
== Свойства ==<br />
<br />
Общие для всех объектов свойства описаны в документе [[Object|Object]].<br />
Дополнительные свойства:<br />
<br />
* '''Состояние''' - Состояние в котором будет находиться машина при инициализации. Если ничего не указано - первое состояние в списке состояний.<br />
* '''Хранить нажатость''' - нужно ли сбрасывать нажатость при изменении состояния.<br />
* '''res''' - графический ресурс машины. Может отсутствовать. Перетягивается из редактора ресурсов(поле должно быть в состоянии редактирования).<br />
* '''states''' - По двойному клику, или по нажатию на кнопку с тремя точками открывается список состояний.<br />
* '''прокликиваемая''' - 0 - машина не пропускает клик, 1 - машина пропускает клик, 2 - машина обрабатывает клик и пропускает его дальше.<br />
<br />
== Инициализация ==<br />
<br />
При попадании в состояние, сразу выполняются команды инициализации init, draw, set, buy, var. Если в этих командах нет параметра break, они все выполняются до запуска процессов. Параметр break (со значением 1) прерывает выполнение команд инициализации данного типа. Их можно перезапустить по окончанию команд процессов.<br />
<br />
=== draw ===<br />
<br />
Команда определяет графический ресурс (картинку, которую надо рисовать в данном состоянии). Её параметры:<br />
<br />
* '''res''' - ресурс картинки (перетаскивается из редактора ресурсов);<br />
* '''f''' - начальный кадр;<br />
* '''ft''' - длительность кадра в миллисекундах;<br />
* '''loop''' - число повторов (зацикливаний анимации); если -1, то бесконечно; отсутствует или 0 - будет проигран одина раз;<br />
* '''go''' - перейти в состояние;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия перехода; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Пустая команда draw (без параметров) "сбрасывает" текущую картинку и в этом состоянии ничего рисоваться не будет. Если в общих параметрах объекта (в базовой панеле свойств) задан ресурс рисования, и он во всех состояниях одинаков, то его можно в состоянии не задавать.<br />
<br />
Если параметра loop нет, кадры анимации проиграются один раз. Чтобы зациклить их, необходимо установить loop=-1 или нужное число раз. Аналогично параметру loop других команд, первый раз draw выполняется в любом случае. Дальнейшие её повторы определяются значением loop. Однако, в отличие от других команд, loop повторяет только '''данную''' команду draw (даже если она не первая).<br />
Для работы loop '''необходимо''' чтобы в редакторе ресурсов в настройках анимации '''было отключено''' зацикливание(looped).<br />
<br />
=== init ===<br />
<br />
Инициализация параметров данной машины<br />
<br />
* '''x''','''y''' - координата точки пивота относительно сцены или родительского объекта;<br />
* '''sx''','''sy''' - масштаб машины по осям (если 1, то это исходный размер; 0.5 - в два раза меньше);<br />
* '''ang''' - угол поворота в градусах; отчитывается вниз от оси x, или вверх, если отрицательный;<br />
* '''v''' - скорость для команды move<br />
* '''vr''' - угловая скорость для команды rot<br />
* '''vx''','''vy''' - начальная скорость для команды phys<br />
* '''ax''','''ay''' - ускорение для команды phys<br />
* '''z координата''' - координата машины по z.<br />
* '''z приращение''' - приращение координаты машины по z относительно текущего<br />
* '''vis''' - видимость - видимость машины (1 - видима, 0 - невидима)<br />
* '''показать рейтинг''' - значение 1 означает, что при выполнении этого инита будет показано окно iOS рейтинга<br />
* '''закрыть приложение''' - значение 1 означает, что при выполнении этого инита приложение будет закрыто<br />
* '''перезагрузить лэйаут''' - значение 1 означает, что при выполнении этого инита будет перезагружен лэйаут<br />
* '''вернуться назад''' - начение 1 означает, что при выполнении этого инита произойдет возврат на предыдущий экран<br />
* '''реклама AdMob''' - 1 - показать, 0 - спрятать, -1 - не изменять состояние<br />
* '''прокликиваемая''' - если 1, то картинка прозрачна для клика мышкой (пропускает объектам под ней). Если 2, то клик обрабатывается, но передается дальше<br />
* '''курсор''' - меняет текущий курсор мыши на указанный графический ресурс. Перетягивается из редактора ресурсов, поле должно быть в состоянии редактирования.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] для условия выполнения; можно использовать логические операторы (см. [[#if|if]]);<br />
* '''break''' - прервать команды.<br />
<br />
Так же, как и при инициализации картинки ('''draw'''), вызов команды ('''init''') переопределяет только те параметры, которые в ней указаны. Остальные параметры (заданные в других состояниях или в общих свойствах объекта) остаются без изменений<br />
<br />
=== set ===<br />
<br />
Перевод другого объекта в некоторое состояние или изменение его параметров.<br />
<br />
* '''obj''' - изменяемый объект (выбирается из списка объектов);<br />
* '''st''' - состояние в которое переводится объект.<br />
* '''scr_param''' - глобальный либо текущий экран, параметры которого меняем<br />
* '''scr_state''' - экран, состояние которого меняем<br />
* '''parent''' - Объект, который будет установлен в качестве родителя объекту из obj. Объект obj будет оторван от текущего своего родителя и добавлен в детей объекта parent<br />
* '''scr_obj''' - у какого экрана надо изменить состояние st либо параметры.<br />
* '''par''' - параметр объекта для установки, используется вместе с val, val_obj, val_txt, val_scr.<br />
* '''val''' - значение параметра объекта для установки<br />
* '''round''' - округлить значение, записываемое в val<br />
* '''val_obj''' - id объекта, будет записано в в par<br />
* '''val_txt''' - id текста, будет записано в в par<br />
* '''val_scr''' - id экрана, будет записано в в par<br />
* '''val_res''' - Новое значение графического ресурса (перетаскивается из редактора ресурсов). (пока не работает)<br />
* '''var''' - имя переменной данной машины, значение которой присваивается в параметр par объекта obj<br />
* '''scr''' - экран на который мы хотим перейти<br />
* '''user''' - 1 - сохранять значения для текущего пользователя. Для всех типов объектов кроме options этот флаг игнорируется<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] при выполнении которого происходит отработка команды set. <br />
* '''break''' - прервать выполнение команд set на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Так как все объекты (не только машины) имеют состояния, то при помощи команды set можно их менять. Стоит обратить внимание на то, что когда в параметрах (любых команд) встречается st, речь идет о состоянии другого объекта, а если go, то данной машины состояний.<br />
<br />
=== play ===<br />
<br />
Проиграть звук.<br />
<br />
*'''snd''' - короткий звук (перетаскивается из редактора ресурсов);<br />
*'''voice''' - голос (запускается как звук, но без цикла и с громкостью голоса) (перетаскивается из редактора ресурсов);<br />
*'''mus''' - длинный звук (перетаскивается из редактора ресурсов);<br />
*'''preload''' - указанный звук будет загружен в память, но не будет проигрываться прямо сейчас. Для ускорения его старта потом;<br />
*'''loop''' - зациклить звук (звуки);<br />
*'''mus_stop''' - остановить текущую музыку (''mus_stop=1'');<br />
*'''volume''' - установить громкость для всех звуком данной машины - тех что уже играют и тех, что будут запущены впоследствии;<br />
*'''if''' - номер (начиная с нуля) условия перехода [[#if|if]].<br />
<br />
Особенности примененияния:<br />
<br />
*Короткий звук (''snd'') нельзя запустить в первом (инитном) состоянии машины. Для того, чтобы запустить звук сразу при загрузке экрана, нужно в первом состоянии машины записать мгновенный переход во второе состояние мамашины (например, команда ''wait'', поле ''go'', в поле выбрать второе состояние), а во втором состоянии уже запустить звук. Если звук нужно зациклить и проигрывать какое-то количество раз (''loop=1,2,3,..,n'') или бесконечно (''loop=-1''), то нужно проследить чтобы состояние, в котором запускается звук, не вызывалось повторно во время проигрывания звука, иначе возникнет наложение звуков. Если во время проигрывания звука машина меняет свое состояние, звук продолжает играть. Если в одной машине почти одновременно воспроизводится несколько звуков, то они прерывают друг друга. Если каждый звук воспроизводится в отдельной машине, то они звучат параллельно.<br />
*Длинный звук (''mus'')- музыка. На экране не может воспроизводится несколько длинных звуков одновременно. Любой запуск длинного звука независимо от того, в какой машине он осуществляется, будет прекращать проигрывание предыдущего звука. Музыка, которая проигрывается на глобальном экране, проигрывается на всех экранах проекта.<br />
<br />
=== var ===<br />
<br />
Переменная, которой присваивается значение параметра объекта<br />
<br />
*'''name''' - имя переменной;<br />
*'''obj''' - объект, используемый далее;<br />
*'''par''' - имя параметра, значение которого присваивается переменной;<br />
*'''val''' - значение переменной, если отсутствуют obj и par;<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
<br />
Обозначенная переменная существует (может использоваться) только в текущем состоянии. Переменная может определятся в одном состоянии только один раз. Если созданной переменной нужно изменить значение в рамках состояния, это можно сделать через другую переменную или через параметр опций ([[Options]]). Если ее значение нужно использовать в другом состоянии, то оно присваивается параметру опций, а затем заново считывается в новом состоянии. Переменные можно указывать в поле ''val'' с другими математическими действиями и цифрами, при этом каждое действие заключать в скобки. Если в поле ''val'' указать имя переменной ''А'' без скобок - воспримется строка ''А'', если указать в скобках - воспримется значение переменной.<br />
<br />
=== buy ===<br />
<br />
При переходе в состояние, данная команда открывает системное окно с предложением совершить in-app покупку. В зависимости от действий игрока, покупка может произойти (успех) или не произойти (провал).<br />
<br />
* '''id покупки''' - внутренний id покупки для приложения, указывается в объекте [[Store]];<br />
* '''объект(успех)''' - объект, которому сообщается об удачной покупке;<br />
* '''состояние(успех)''' - состояние в которое переводится выбранный объект в случае успешной покупки;<br />
* '''объект(провал)''' - объект, которому сообщается о неудачной покупке;<br />
* '''состояние(провал)''' - состояние в которое переводится объект в случае неудачной покупки.<br />
<br />
== Процессы ==<br />
<br />
Все команды процессов, кроме параметров описанных ниже, могут содержать параметры, совпадающие с именами других команд. В этих параметрах указывается номер (начиная с нуля) команды, которую надо запустить на выполнение, после окончания действия данной команды процесса.<br />
<br />
Если в команде процесса есть условие '''[[#if|if]]''', то после окончания работы команды она ждет пока это условие не выполнится. Только после этого переходит к следующей команде этого же типа<br />
или в другое состояние (если есть параметр go).<br />
Исключением является команда wait, которая '''не''' ждёт срабатывания '''[[#if|if]]'''. Если он по окончанию wait сработал, то происходит переходит в другое состояние, если есть параметр go.<br />
Если параметра go нет, то в любом случае запускается следующий wait (т.е. if относится только к переходу go).<br />
<br />
=== wait ===<br />
<br />
Команда паузы (временной задержки). Если параметра '''t''' нет, то срабатывает сразу.<br />
Может также использоваться для логических ветвлений, случайных переходов в другие состояния и т.д.<br />
<br />
* '''t''' - длительность выполнения команды в ms;<br />
* '''dt''' - интервал от t-dt до t+dt, внутри которого команда может быть случайно прервана (при t>t+dt прерывается в любом случае);<br />
* '''p''' - вероятность срабатывания перехода в состояние, указываемое параметром go;<br />
* '''go''' - состояние, в которое нужно перейти поле окончания времени и срабатывания условия [[#if|if]], если оно указано;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go;<br />
* '''loop''' - зациклить команды;<br />
* '''break''' - прервать выполнение команд wait на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Простейший набор параметров команды wait выглядит следующим образом:<br />
<pre><br />
<wait t="1000" go="next"/> // ждем 1000ms и покидаем состояние<br />
</pre><br />
Для программирования объектов со случайным поведением можно использовать последовательность команд wait с параметром вероятности перехода p (от 0 до 1):<br />
<pre><br />
<wait t="100" p="0.5" go="st1"/> // через t с вероятностью 1/2 перейдет в st1<br />
<wait go="st2"/> // иначе, перейдем в st2<br />
</pre><br />
Этот же синтаксис позволяет делать состояния с различным временем жизни:<br />
<pre><br />
<wait t="100" p="0.5" go="next"/> // с вероятностью 1/2 живем 100ms<br />
<wait t="100" go="next"/> // или 200ms<br />
</pre><br />
Впрочем, последнюю задачу можно решить при помощи указывания интервала dt, внутри которого произойдет окончание команды. Так, состояние, живущее от 800 до 1200ms, реализуется следующим образом:<br />
<pre><br />
<wait t="1000" dt="200" go="next"/><br />
</pre><br />
<br />
=== move ===<br />
<br />
Перемещение по сцене:<br />
* '''tx''', '''ty''' - целевые координаты в пикселях, к которым должен переместиться объект;<br />
* '''dx''', '''dy''' - величина смещения от текущей (если есть - tx,ty игнорируются); можно задавать смесь tx, dy или dx,ty;<br />
* '''v''' - скороcть перемещения в пикселях в секунду; для фреймовой анимации, например, ходьбы скорость рассчитывается исходя из длительности одного кадра и числа кадров на фазу движения. Поэтому, в этом случае, удобнее задавать скорость;<br />
* '''t''' - время перемещения (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду move, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд move на этой команде (запустить их снова можно из команд процессов).<br />
<br />
В большинстве команд процессов, связанных с движением, величина изменения может быть задана в абсолютных или относительных величинах. Так, могут быть указаны целевые координаты tx, ty в которые надо переместиться, или смещение dx, dy относительно текущего положения объекта.<br />
<br />
Аналогично, скорость перемещения регулируется, либо явным заданием времени выполнения команды t, либо скоростью v. Исходя из требуемого расстояния, по этой скорости вычисляется необходимое время. Скорость задается в пикселях за cекунду (а не миллисекунду!)<br />
<br />
=== rot ===<br />
<br />
Вращение объекта вокруг точки пивота с координатами px,py. Эти координаты задаются относительно верхнего левого угла объекта в общей секции описания параметров объекта или командой init в данном состоянии.<br />
* '''ta''' - целевой угол поворота объекта;<br />
* '''da''' - на сколько надо повернуться (ta игнорируется);<br />
* '''v''' - угловая скорость поворота в градусах в секунду;<br />
* '''t''' - время поворота (v игнорируется);<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду rot, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд движения с первой команды;<br />
* '''break''' - прервать команды - Прервать выполнение команд rot на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Угол отсчитывается от оси x. Если он положителен, то поворот происходит по часовой стрелке. Если отрицательный - против часовой.<br />
<br />
=== alpha ===<br />
<br />
Изменение прозрачности объекта. Меняется от 0 (полностью прозрачен) до 1 (непрозрачен)<br />
* '''ta''' - целевая прозрачность<br />
* '''da''' - на сколько надо изменить прозрачность от текущей (ta игнорируется)<br />
* '''v''' - скорость изменения прозрачности (в долях единицы в ms)<br />
* '''t''' - время изменения (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду alpha, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд alpha с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд alpha на этой команде (запустить их снова можно из команд процессов).<br />
<br />
Если у объекта прозрачность ''al=0.00'', то он невидим для всякого взаимодействия. Если у объекта прозрачность ''al=0.01'', то он видим для клика, но невидим для дропа(команда drop на объект не видит объект с прозрачностью ''0.01''). Если у объекта ''al=0.02'', то он видим и для клика, и для дропа.<br />
<br />
=== scale ===<br />
<br />
Изменение размеров объекта<br />
* '''tx''', '''ty''' - целевой масштаб по каждой оси<br />
* '''dx''', '''dy''' - на сколько изменить масштаб по каждой оси<br />
* '''v''' - скорость изменения масштаба (в долях единицы в сек.)<br />
* '''t''' - длительность выполнения команды (v игнорируется)<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду scale, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд scale с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд scale на этой команде (запустить их сново можно из команд процессов).<br />
<br />
=== phys ===<br />
<br />
Команда phys позволяет имитировать простую физику. В ней задается начальная скорость и действующая на объект сила (ускорение).<br />
<br />
* '''vx''', '''vy''' - начальная скорость<br />
* '''ax''', '''ay''' - величина ускорения по каждой оси<br />
* '''tvx''', '''tvy''' - целевая скорость<br />
* '''tx''', '''ty''' - целевая координата<br />
* '''go''' - новое состояние - Состояние в которое нужно перейти после окончания времени.<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]], при выполнении которой происходит переход go; команда ждет срабатывания условия, и не запускает следующую команду phys, пока if не выполнится; <br />
* '''loop''' - зациклить команды - Начать выполнение команд phys с первой команды.<br />
* '''break''' - прервать команды - Прервать выполнение команд phys на этой команде (запустить их снова можно из команд процессов). <br />
<br />
Рассмотрим подпрыгивающий мячик, который при касании с землей деформируется (вертикально сплюскивается). Это можно сделать в 3 состояния (падаем, касаемся и взлетаем). Первоначально мячик находится в координте y=-100, и имеет высоту картинки w=60. Падает он до координаты ty=0. При касании с землёй, мяч сжимается на 20 процентов (sy=0.8). При этом его центр должен опуститься на dy=0.8*w/2 = 24.<br />
<pre><br />
<br />
<st id="down"> // падаем<br />
<phys vy="0" ay="20" ty="0" go="touch"/><br />
</st><br />
<br />
<st id="touch"> // касаемся земли<br />
<move dy="24" t="300"/> // опускаем центр при сжатии<br />
<scale ty="0.8" t="300"/> // сжимаемся<br />
<move dy="-24" t="300"/> // поднимаем центр при разжатии<br />
<scale ty="1" t="300" go="up"/> // разжимаемся<br />
</st><br />
<br />
<st id="up"> // взлетаем<br />
<phys vy="0" ty="-200" go="down"/><br />
</st><br />
<br />
</pre><br />
Напомним, что если объект имеет начальную скорость взлета, равную v=sqrt(2*ay*h), то он подпрыгнет на высоту h. Однако, в данном случае, вместо задания начальной скорости при взлете, мы задаем целевую координату (ty), до которой мяч должен подпрыгнуть.<br />
<br />
== Воздействия ==<br />
<br />
=== click ===<br />
<br />
Команда вызывается, если на объект кликнули мышкой. Срабатывает на её нажатие.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_in ===<br />
<br />
Наведение мыши/пальца на машину, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== touch_out ===<br />
Выведение мыши/пальца из машины, если палец "тащат" по экрану.<br />
* '''go''' - состояние в которое при клике надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при котором срабатывает переход go.<br />
<br />
=== mouse_in ===<br />
<br />
Срабатывает при наведение мыши/пальца на машину даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== mouse_out ===<br />
Срабатывает при выведение мыши/пальца из машины даже если не нажата кнопка мыши, работает на desktop-ных системах (OSX, Windows)<br />
* '''go''' - состояние в которое при выполнении команды надо перейти (если if нет, то в любом случае);<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]], при срабатывании которого, происходит переход go.<br />
<br />
=== drag ===<br />
<br />
Если на объект наступили мышкой, и не отпуская его, начали перемещать, то при наличии этой команды, объект "прилипнет" к мышке, и будет за ней таскаться. Можно ограничить разрешенную область таскания, за которую объект выпускаться не будет. <br />
* '''x1''' - разрешено таскать, когда координата объекта правее;<br />
* '''x2''' - разрешено таскать, когда координата объекта левее;<br />
* '''y1''' - разрешено таскать, когда координата объекта ниже;<br />
* '''y2''' - разрешено таскать, когда координата объекта выше;<br />
* '''if''' - номер команды условия (начиная с нуля) разрешения таскания;<br />
* '''obj''' - объект у какоторого надо изменить состояние;<br />
* '''st''' - новое состояние объекта obj;<br />
* '''таскать за пивот''' - 1 - таскать объект за пивот, 0 - за ту точку, за которую схватили<br />
<br />
=== drop ===<br />
<br />
Если нажатая кнопка мышки отпускается, вызвается эта команда. Обычно она используется в связке с командой drop<br />
* '''obj''' - объект, на который надо уронить таскаемый объект;<br />
* '''go''' - состояние в которое переходим при отпускании мышки;<br />
* '''if''' - номер (начиная с нуля) условия [[#if|if]] разрешения бросания.<br />
<br />
Рассмотрим совместное применение команд drag и drop на следующей задаче. Пусть есть ключ и ящик. Ключ можно взять мышкой и перетащить, бросив на ящик. Ящик при этом должен постепенно стать прозрачным, а ключ уменьшиться до нуля. Машина состояний для ключа выглядит следующим образом:<br />
<pre><br />
<br />
<st id="drag"><br />
<drag x1="-350" x2="350" y1="-250" y2="250"/><br />
<drop obj="box" go="open"/><br />
</st><br />
<br />
<st id="open"><br />
<set obj="box" st="open"/><br />
<scale tx="0.01" ty="0.01" t="500" go="hide"/><br />
</st><br />
<br />
<st id="hide"><br />
<init x="268" y="30"/><br />
<scale tx="1" ty="1" t="500" go="drag"/><br />
</st><br />
<br />
<br />
</pre><br />
Ящик:<br />
<pre><br />
<br />
<st id="close"> // начальное состояние ящика<br />
<init al="1"/> // если его кто-то сюда переведет - он появится.<br />
</st><br />
<br />
<st id="open"> <br />
<alpha ta="0" t="500"/> // исчезает по прозрачности за 500 ms<br />
</st><br />
<br />
</pre><br />
<br />
=== throw ===<br />
<br />
Если на объект наступили мышкой, не отпуская кнопки, мышку оттащили и затем отпустили, вызывается команда throw со следующими параметрами:<br />
* '''go''' - состояние, в которое, при клике, надо перейти;<br />
* '''if''' - номер (начиная с нуля) команды [[#if|if]] разрешения бросания;<br />
* '''force''' - получаемая скорость равна разнице пискелей от начала бросания (мышь нажата) до его конца (мышь отжата), умноженная на этот параметр. По умолчанию он равен 1.<br />
<br />
Сработав, эта команда задает начальные значения скорости для команды phys, поэтому должна использоваться совместно с ней (см. ниже пример).<br />
<br />
=== apply ===<br />
<br />
Вызывается, если данная машина пересеклась с другой. Обычно используется в совокупности с throw, move, phys, drag.<br />
* '''obj''' - сработает , если пересеклись с этим объектом;<br />
* '''x1''' - сработает, если центр объекта левее этого x-ка;<br />
* '''x2''' - сработает, если центр объекта правее этого x-ка;<br />
* '''y1''' - сработает, если центр объекта выше этого y-ка;<br />
* '''y2''' - сработает, если центр объекта ниже этого y-ка;<br />
* '''rm''' - радиус этой машины (если rm=0, то она считается прямоугольной)<br />
* '''ro''' - радиус объекта obj (если ro=0, то он считается прямоугольным)<br />
* '''st''' - состояние, в которое надо перевести объект obj<br />
* '''go''' - состояние, в которое надо перейти при срабатывании;<br />
* '''if''' - номер (начиная с нуля) команды условия [[#if|if]] разрешения применения команды apply.<br />
<br />
<br />
Пусть, например, есть снаряд, который при помощи мышки надо кинуть в "тыкву". Если мы промахнулись, снаряд должен вернуться обратно, а с тыквой ничего не произойти. Если мы в тыкву попадаем, снаряд также возвращается, а тыква "взрывается":<br />
<pre><br />
<br />
<st id="trow"><br />
<init x="-350" y="150"/> // начальное положение<br />
<throw go="fly"/> // бросаем<br />
</st><br />
<br />
<st id="fly"><br />
<phys ay="100"/> // летим<br />
<apply y2="300" go="throw"/> // с землей<br />
<apply obj="тыква" rm="8" ro="10" st="bang"/> // с тыквой<br />
</st><br />
<br />
</pre><br />
<br />
== Условия ==<br />
<br />
=== if ===<br />
<br />
В состоянии может быть произвольное число команд if. Их номера (начиная с нуля) указываются<br />
в параметре if других команд. Эти номера можно соединять при помощи логических связок:<br />
* '''&''' - логическое '''и''' (вместо значка '''&''' можно использовать запятую ''',''');<br />
* '''|''' - логическое '''или''';<br />
* '''!''' - логическое '''не'''.<br />
Пример записи логического выражения в поле if некоторой команды: '''(1&2)|(3&(!4))''',<br />
что означает: выполняется if под номером 1 и под номером 2, или под номером 3 и не под номером 4.<br />
<br />
Логические связки используются также как математической логике или любом языке программирования. <br />
Так:<br />
* A '''&''' B - истинно, если истинны оба условия A и B;<br />
* A '''|''' B - истинно, если истинно хотя бы одно условие (или оба);<br />
* '''!''' А - истинно, если условие A ложно.<br />
Скобки в логическом выражении определяют приоритет (порядок) выполнения логических операций.<br />
Отметим несколько тождеств, справедливых при формировании логических высказываний:<br />
* !(A & B) = (!A) | (!B)<br />
* !(A | B) = (!A) & (!B)<br />
* !(!A) = A<br />
<br />
Если при формировании условия (ниже) есть несколько проверок, то они соединены логическим '''и'''.<br />
Т.е., если хотя бы одна из них не выполняется, то считается, что условие не выполнилось.<br />
<br />
Параметры команды:<br />
* '''obj''' - находится ли объект obj в состоянии st или имеет ли его параметр par значение val;<br />
* '''st''' - имя состояния в котором может находиться объект obj;<br />
* '''par''' - имя параметра объекта obj, значение которого сравнивается с полем val;<br />
* '''val''' - значение параметра par, которое проверяется у объекта obj;<br />
* '''op''' - операция сравнения par op val. Если опреации нет, то предполагается проверка на равенство par=val. Иначе используются операторы:<br />
** '''<''' - меньше (par < val);<br />
** '''>''' - больше (par > val);<br />
** '''!=''' - не равно (par != val);<br />
** '''<>''' - не равно (par <> val);<br />
** '''>=''' - больше или равно (par >= val);<br />
** '''<=''' - меньше или равно (par <= val);<br />
* '''curScr''' - если текущий экран совпадает с этим, то условие выполнилось;<br />
* '''prScr''' - если предыдущий экран совпадает с этим, то условие выполнилось;<br />
* '''wasScr''' - если был (когда либо) этот экран, то условие выполнилось.<br />
* '''buy''' - был ли куплен данный inn-app (проверяется флаг поля в объекте [[Options]]);<br />
* '''url''' - валиден (правилен и может быть запущен) ли данный интернет-адрес;<br />
* '''is_mus''' - играет ли сейчас музыка (значение 1);<br />
* '''guest''' - объект который установил состояние (используется вместо параметра obj). Если указанный объект не менял состояние этой машины, то условие не срабатывает.<br />
<br />
Если использовать obj, par, val, то будет происходить проверка на равенство значения параметра объекта и значения записаного в поле val.<br />
Если же использовать obj, par, op, val, то будет происходить проверка в соответствии с операцией сравнения значения параметра объекта и значения записанного в поле val.<br />
<br />
== Математика ==<br />
Математика в appsalute creator представлена 4-мя основными операциями: (плюс), (минус), (умножить), (поделить) <br><br />
Организована благодаря совместному использованию '''[[#var|var]]''' и '''[[#set|set]]'''. <br />
=== var ===<br />
Благодаря использованию '''[[#var|var]]''' существует возможность cчитать любой числовой параметр любого объекта. Например: x - координату какой-то машины, текущее значение любого объекта counter или timer и конечно же считывание значения любого параметра из опций! Каким образом это устроено? Рассмотрим подробнее '''[[#var|var]]''': <br><br />
[[Файл:VAR.png|right]]<br />
*'''name''' - здесь выбираем имя для нашей будущей переменной, которой будем оперировать далее<br />
*'''obj''' - выбирается объект, параметры которого мы хотим считать<br />
*'''par''' - параметр, который нужно вычитать из объекта, указанного выше<br />
*'''val''' - указывается числовое значение, которое будет установлено по умолчанию в случае отсутствия obj и par<br />
*'''user''' - если стоит "1", то будет считываться с текущего профиля в опциях<br />
На изображении справа можно наблюдать каким образом организован '''[[#var|var]]'''. В данном случае объявлена переменная x_cor, которая cчитывает x-координату объекта actor_1, при этом cчитывание переменной происходит из текущего профиля, так, как в поле user установлено значение равное "1".<br />
<br />
=== set ===<br />
[[Файл:SET.png|right]]<br />
Использование '''[[#var|var]]''' без '''[[#set|set]]''' не имеет смысла. Так, как переменная создается, но не используется дальше. Рассмотрим следующий пример, где вычитаем x - координату из одного объекта и сохраним ее в опции, предварительно увеличив ее на 50 единиц (в данном случае 50 пикселей).<br />
На рисунке справа можно наблюдать, каким образом это сделано. В состоянии '''init''' объявляется переменная '''x_cor''', которая cчитывает координату '''x''' из объекта '''actor_1''', таким образом в переменную '''x_cor''' запишется положение по '''x''' объекта '''actor_1'''. Поле '''user''' в данном случае в '''1''' не обязательно устанавливать, так как работа ведется с машинами, а не с опциями. Если бы на месте '''actor_1''' оказался объект '''options''', то это было бы просто необходимо, иначе программа считает значение не из профиля. Далее в '''[[#set|set]]''' выбран объект '''options''', в параметр '''x_position''' которого будет сохранятся значение переменной '''x_cor''' увеличенной на 50. В поле '''round''' идет округление вычисляемого значения, если оно установлено в 1. Поле '''user ''' установлено в 1, это значит, что параметр '''x_position''' будет сохранен в профиль. После это выполняется сохранение опций путем задания объекту '''options''' состояния '''save'''.<br><br />
! ! !ВАЖНО: чтобы выполнить какие-то действия с '''[[#var|var]]''' его обязательно нужно указывать в поле '''val''' в '''set''', при этом, если он используется, то все выражение должно стоять в скобках. Если в поле '''val''' не используется переменная, то скобки необязательны.<br />
<br><br />
<br><br />
<br><br />
<br><br />
Существует также возможность использовать '''[[#var|var]]''' совместно с '''[[#if|if]]''', а также '''[[#var|var]]''' с '''[[#move|move]]'''<br />
<br><br />
<br><br />
<br><br />
<br />
=== var и if ===<br />
[[Файл:IF.png|right]]<br />
При подробном рассмотрении '''[[#if|if]]''' можно заметить, что в нем есть поле '''val''', соответственно в этом поле можно указать переменную. Таким образом в поле '''val''' необязательно указывать константу, а можно указать какую-то переменную, которая может постоянно изменяться. Например, существует два объекта, один находится состоянии покоя, а другой находится в движении. При этом первый объект (тот, который в состоянии покоя) постоянно опрашивает положение второго объекта, и в случае, если у объекта, который движется, '''х''' координата равна '''х''' координате первого объекта, то первый объект входит в состояние, где он начинает свое движение. На рисунке показан объект, который находится в состоянии покоя, рассмотрим его состояния:<br><br />
В данном объекте существует два состояния: '''init''' и '''move'''. В '''init''' объект опрашивает другой объект и в случае, когда условие срабатывает, то переходит в состояние '''move''', где начинает свое движение.<br />
В '''init''' создаем переменную, в которую записываем положение по '''x''' объекта '''actor_2''', в '''if''' проверяется условие на соответствие координат объектов '''actor_1''' и '''actor_2''', в данном случае координата объекта '''actor_2''' представлена в виде переменной '''x_cor'''. Если условие выполняется, то происходит переход в состояние '''move''', если нет, то заново проходим состояние '''init''' и повторяем вышеописанную последовательность действий.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
=== var и move ===<br />
Также с помощью '''[[#var|var]]''' есть возможность указать целевые координаты в '''[[#move|move]]'''. То есть, не обязательно указывать целевые координаты в виде констант, их можно указать теперь с помощью переменных. При использовании '''[[#var|var]]''' и '''[[#move|move]]''' можно организовать обмен двух объектов местами с анимацией движения. Для этого необходимо определять какой объект нажат первым, а какой вторым, сохранять их координаты через объект '''options''' и только потом менять их местами. На рисунке можно увидет, как это организовано.<br />
[[Файл:var_move.png|1000px|thumb|center|]]<br />
Рассмотрим подробнее состояние данной машины:<br />
<br><br />
* '''init'''<br><br />
В этом состоянии ожидаем клик на объект и обнуляем параметр, который отвечает за то, какой по счету объект сейчас нажат. Так, как при обмене объектов, если мы делаем это по клику, важно знать, по какому кликнули нажали первым, а по какому вторым.<br />
* '''check'''<br><br />
Проверяется параметр '''number''', если он равен '''0''', то это значит, что еще ничего не кликали и мы переходим в состояние, где в опции записываются координаты этого объекта, который считается нажатым первым. Если не равен '''0''', то считается, что этот объект нажат вторым и переходит в состояние, где в опции записываются координаты этого объекта, который считается нажатым вторым по счету.<br />
* '''first_object'''<br><br />
В этом состоянии записываются координаты объекта в опции. Чтобы записать координаты в опции используются '''[[#var|var]]''' и '''[[#set|set]]''' упоминаемые выше. В опции координаты первого нажатого объекта сохраняются под параметрами '''x_first''' и '''y_first'''. В конце параметру '''number''' присваиваем значение '''1''', чтобы указать, что следующий нажатый объект будет вторым по счету. <br />
* '''second_object'''<br><br />
В этом состоянии объект будет в том случае, если он будет нажатым вторым по счету, то есть после состояния '''check''' объект попадет в это состояние, где он запишет свои текущие координаты под параметрами '''x_second''' и '''y_second'''. Запись координат происходит таким же самым образом, что и в состоянии '''first_object'''. После этого он автоматически переходит в следующее состояние.<br />
* '''move_first'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат первым, поэтому он будет двигаться на место второго нажатого объекта, который сохранил свои координты в параметры'''x_second''' и '''y_second'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты второго объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
* '''move_second'''<br><br />
В этом состоянии объект будет в том случае, если он был нажат вторым, поэтому он будет двигаться на место первого нажатого объекта, который сохранил свои координты в параметры '''x_first''' и '''y_first'''. Движение происходит следующим образом: сперва в переменную вычитываем координаты первого объекта, а потом в '''move''' вместо целевых координат записываем переменные, которые обязательно должны быть взяты в скобки.<br />
<br />
В результате проделанных манипуляций с машинами по кликам на две машины, они обменяются местами с анимацией движения. Это может быть очень полезным во многих минииграх!!!<br />
<br />
=== Важно знать ===<br />
* Переменная действует в рамках одного состояния, если нужно, чтобы она была глобальной, нужно сохранить ее в опции и потом в нужный момент считывать ее из опций.<br />
* Если складываем два числа, то в поле '''val''' они должны быть записаны в скобках: (5+3).<br />
* Если возникает необходимость написать какое-то более сложное арифметическое вычисление, то следует помнить, что на одно действие приходятся одни скобки. Например: (((5+3)\2)*2).<br />
* Количество открывающих и закрывающих скобок должно быть одинаковым.<br />
* В скобках можно писать переменную, если она была объявлена выше: (5+a).<br />
* Переменная может состоять из цифр и букв и знака нижнего подчеркивания.<br />
* Иногда бывает необходимым использование '''round''' в '''set''', так например, если какой-то параметр получен с помощью арифметических вычислений и потом используется его в каком-то условии, и условие проверяет параметр, как целочисленное значение, то могут возникнуть ошибки. Так, как число будет записано в следующем виде 123.0000 и программа будет считать, что оно не целочисленное, а дробное. И чтобы избавится от лишних нулей в дробной части следует округлять число.<br />
* Действия, которые требуют времени, такие как move, rot, wait и другие перестают работать для уменьшения вычислительной нагрузки на устройство.<br />
* Действия, которые не требуют времени, такие как set, init и другие продолжают функционировать.<br />
<br />
<br />
<pre><br />
Если с помощью переменной менять объекту любой параметр, например, координату X, то она запомнится (запишется как значение по умолчанию).<br />
Тогда при повторном попадании на экран считается не тот X, который указан в свойствах, а тот, который установлен через переменную.<br />
Если нужно при ините экрана возвращать начальные значения параметров, то можно сделать это двумя способами:<br />
- не использовать переменную;<br />
- создать отдельное состояние, которое будет "вручную" устанавливать начальные значения параметрам при ините экрана.<br />
Если координата (или другой параметр) меняется другим способом, то будут автоматически при ините экрана подтягиваться значения из свойств объекта.<br />
</pre><br />
<br />
=== Примеры применений ===<br />
С помощью математики можно организовать следующее:<br />
* динамические опции (изменение звука и музыки с помощью ползунка);<br />
* анимацию каунтера в играх (по окончанию уровня можно наблюдать, как изменяются очки);<br />
* подсчет очков (гибкая система подсчета очков);<br />
* обмен объектов местами (использование var и move)<br />
* увеличение z-координаты любого объекта (когда необходимо, чтобы нажатый или таскаемый объект был выше других по z);<br />
* простейший калькулятор;<br />
* и много других.<br />
<br />
== Random ==<br />
На момент, когда пишется данная статья, понятие вероятности существует только в команде wait и в текстовом поле(объект [[Text]]) можно показать случайный текст. Однако, и текущей функциональности достаточно, чтобы сделать генератор случайных чисел:<br />
[[Файл:Random.jpg]]<br />
Или в виде xml:<br />
<nowiki><br />
<obj type="machine" id="<Вставьте сюда ваш идентификатор объекта>" nm="random" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<br />
<st id="init"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.precision" val="0.01" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
<st id="count"><br />
<br />
<set obj="369" par="random.val" val="0" user="1"/><br />
<br />
<set obj="369" par="random.add" val="1" user="1"/><br />
<br />
<set obj="369" st="save"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="iterate"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<set obj="369" par="random.add" val="((add)/2)" user="1"/><br />
<br />
<wait if="0" go="complete"/><br />
<br />
<wait p="0.5" go="add"/><br />
<br />
<wait go="iterate"/><br />
<br />
<if obj="369" par="random.precision" op="&gt;" val="(add)"/><br />
<br />
</st><br />
<br />
<st id="add"><br />
<br />
<var nm="add" obj="369" par="random.add" user="1"/><br />
<br />
<var nm="val" obj="369" par="random.val" user="1"/><br />
<br />
<set obj="369" par="random.val" val="(add+val)" user="1"/><br />
<br />
<wait go="iterate"/><br />
<br />
</st><br />
<br />
<st id="complete"><br />
<br />
<set obj="369" st="save"/><br />
<br />
</st><br />
<br />
</obj><br />
</nowiki><br />
<br />
прим. Объект с id="369" - объект типа [[Options]]<br />
<br />
=== Краткое описание алгоритма ===<br />
1. Задаются точность и обнуляется значение(val)<br />
<br />
2. Устанавливается добавляемое значение (add)<br />
<br />
3. add делится на двое. Если срабатывает wait - add добавляется к val. Если add становится меньше допустимой точности - переходим к п. 4. Если не один из переходов не сработал - повторяем п. 3.<br />
<br />
4. Окончание работы объекта, сохранение опций<br />
<br />
=== Как пользоваться? ===<br />
<br />
1. Задаём переменной Options->random.precision необходимую точность (обычно 0.01 для игровых проектов достаточно)<br />
<br />
2. Переводим объект random в состояние count<br />
<br />
3. Ждём определённое время (200 милисекунд, в принципе достаточно, если не успеете - получите результат с меньшей точностью), либо, если уж боитесь - в цикле(переходя wait-ами между 2-мя состояниями) проверяйте перешёл ли random в состояние complete<br />
<br />
4. Результат вычислений заносится в переменную Options->random.val . val принимает значение от 0 до 1 (не включая 1)<br />
<br />
=== Какие могут возникнуть проблемы ===<br />
<br />
1. Если 2 объекта захотят одновременно вызвать random. Решение проблемы: Создать 2 объекта random. И ещё, обязательно переименовать в каждом объекте группу параметров, в который параметры будут заноситься (Например: random1.val, random2.val).<br />
<br />
2. Не следует сохранять в Options промежуточные вычисления, т. к. это очень существенно замедлит вычисления<br />
<br />
3. Если машина невидима(vis = 0), то она остаётся функционировать, но частично:<br />
<br />
Предположим, что есть машина А, у которой перед загрузкой экрана vis=0, в ней в состоянии по-умолчанию есть движение, init и несколько set-ов на другие объекты. При загрузке экрана выполнятся set-ы, init, но объект двигаться как указано не будет.<br />
<br />
Если необходимо чтобы объект двигался невидимым - следует использовать изменение прозрачности машины, или init для перемещения.<br />
<br />
== Random 2 ==<br />
Улучшенный вариант предыдущего генератора случайных чисел ([[Random]]).<br />
Суть состоит в том, что объект записывает переменные внутрь себя, минуя запись объект [Options].<br />
[[Файл:Random2.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4759" type="machine" nm="random_new" sync="1" x="800" y="1200" w="1" h="1" al="0" trace="1"><br />
<st id="init"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="precision" val="0.01"/><br />
<set obj="4759" par="add" val="1"/><br />
</st><br />
<st id="count"><br />
<set obj="4759" par="val" val="0"/><br />
<set obj="4759" par="add" val="1"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="iterate"><br />
<var nm="add" obj="4759" par="add"/><br />
<set obj="4759" par="add" val="((add)/2)"/><br />
<wait if="0" go="complete"/><br />
<wait p="0.5" go="add"/><br />
<wait go="iterate"/><br />
<if obj="4759" par="precision" op="&gt;" val="(add)"/><br />
</st><br />
<st id="add"><br />
<var nm="add" obj="4759" par="add"/><br />
<var nm="val" obj="4759" par="val"/><br />
<set obj="4759" par="val" val="(add+val)"/><br />
<wait go="iterate"/><br />
</st><br />
<st id="complete"/><br />
</obj><br />
</nowiki><br />
<br />
=== Краткое описание алгоритма ===<br />
См. объект [[Random]]<br />
<br />
=== Как пользоваться? ===<br />
См. объект [[Random]]<br />
<br />
=== Достоинства и недостатки ===<br />
Достоинства: можно создавать несколько копий, при этом не нужно лезть внутрь объекта (если хотите иметь несколько генераторов в одном экране, скопируйте генератор в другой экран, а потом перенесите обратно - ссылка внутри объекта на самого себя сохранится).<br />
<br />
Недостатки: Как и в случае с объектом Random, нужно выдержать время, чтобы генератор сработал. Таким образом, к генератору может безопасно обращаться только 1 объект.<br />
<br />
== Random-псевдо ==<br />
Генератор псевдослучайных чисел. Быстрый генератор, по сравнению с [[Random2]].<br />
Суть состоит в том, что последовательность случайных чисел задаётся по формуле.<br />
Хорошее среднее значение (0.47) даёт формула:<br />
A=10000*i*/(i+1)<br />
Даллее, от числа А оставляется только дробная часть.<br />
[[Файл:Random_pseudo.jpg]]<br />
<br />
Исходный xml-код имеет вид:<br />
<br />
<nowiki><br />
<obj id="4908" type="machine" nm="random_pseudo" sync="1" x="800" y="800" w="100" h="100" trace="1"><br />
<st id="init"><br />
<set obj="4908" par="index" val="101"/><br />
<set obj="4908" par="val" val="0"/><br />
</st><br />
<st id="count"><br />
<var nm="a1" obj="4908" par="index"/><br />
<var nm="a" obj="4908" par="a"/><br />
<var nm="ar" obj="4908" par="a_round"/><br />
<set obj="4908" par="a" val="(((a1)/(a1+1))*10000)"/><br />
<set obj="4908" par="a_round" val="(a)" round="1"/><br />
<set obj="4908" par="val" val="(a-ar)"/><br />
<set obj="4908" par="index" val="(a1+1)" if="(!0)"/><br />
<set obj="4908" par="index" val="101" if="0"/><br />
<if obj="4908" par="index" op="&gt;" val="201"/><br />
</st><br />
</obj><br />
</nowiki></div>Atonkonog