Space Engineers Guide

Практическое руководство по Easy Automation 2.0 for Space Engineers

Практическое руководство по Easy Automation 2.0

Overview

Программирование состояния игровых блоков и модулей с помощью скрипта Easy Automation 2.0. Способы отладки, диагностика ошибок и особенности русской локализации.

Что это такое и зачем оно надо

Сразу скажу, что это не перевод документации по Easy Automatition 2.0. Это руководство по организации процесса программирования состояния различных игровых блоков в среде, которую НЕ предоставляют разработчики игры и решение некоторых проблем отладки.

[link]
Итак, Easy Automatition 2.0 (далее просто ЕА2) это интерпретатор команд несложного языка, который придумал автор скрипта для упрощения автоматизации игрового процесса. Он занимает промежуточное положение между ванильной автоматизацией при помощи таймеров и игровыми скриптами на C# и позволяет существенно облегчить создание высоко функциональных крафтов различного назначения.

Как справедливо утверждает автор, с его помощью можно:

  • управлять задержками по таймеру с точность до милисекунд
  • поворачивать роторы на заданный угол
  • двигать поршни на нужную длину
  • выводить состояние любых блоков на LCD экран
  • создавать сложную логику автоматизации и т.п.

Воспользоваться EA2 я решил в процессе создания игровой реплики броневика APC M-577 из фильма “Чужие 2” после того как количество таймеров в нем приблизилось ко 2-му десятку.

[link]
Основная “фишка” APC M-577 – складывающаяся назад турель, которая расположена на 3-м сабгриде – поршень-шарнир-ротор управление которыми и позволяют выставлять ее в боевое и походное положение. Автоматизация этого процесса потребовала установки 7 таймеров, но после добавления скрипта MART, все накрылось… (тут можете сами вставить чем).

Кроме того мне хотелось создать не просто реплику, а, по возможности, боевой крафт и было очевидно, что если во время боя пострадает хотя бы один из таймеров, то вся автоматизация накроется тем же. Один программный блок на корабле защитить гораздо проще, чем пару десятков таймеров и с этой точки зрения у ЕА2 альтернатив нет.

В итоге из APC M-577 получился вполне годная БРДМ, имеющая кроме складывающейся турели, 2-а предустановленных положения подвески, способной выполнять “полицейский разворот” в движении, MART-управление турелью по азимуту, дальномер для определения расстояния до цели и еще кое-что по мелочи.

Желающие могут посмотреть презентацию на Youtube и просмотреть содержимое поля “Свои данные” ЖК-панели LCD Code, где, собственно, и хранится вся там автоматизация, а мы приступим…

Среда обитания

Для организации процесса вам понадобится один программный блок (ПБ), куда нужно будет загрузить сам скрипт, и один дисплей (LCD) для хранения кода в поле “Свои данные”. Для отладки понадобится еще один дисплей с оригинальным именем Debug LCD, но он в принципе, необязателен. Для минимизации объема не нормативной лексики в адрес разработчиков лучше сразу:

1. Назвать ПБ и связанный с ним LCD так, чтобы их можно было быстро найти в панели инструментов фильтром по имени – моем случае используется ключевое слово “Code”.

2. Имя ПБ и LCD лучше сделать короткими, поскольку LCD придется указывать каждый раз когда в цифровую панель кокпита или станции управления помещается программный блок запускающий тот или иной процесс. И то и другое участвует в выводе BuildInfo (см.ниже)

3. Переименовать блоки и группы, связанные с процессом автоматизации по-английски, чтобы минимизировать переключение раскладок клавиатуры. Во встроенном редакторе не работает откат по Ctrl+Z

4. Крайне желательно установить мод BuildInfo, который позволяет в том числе увидеть расширенную информацию в цифровой панели по аргументам, с которыми запускается программный блок. [link]
В итоге должно получиться примерно следующее

.
Сами программы и сообщения, выводимые в процессе, размещаются в 2-х полях настройки самой LCD-панели

.
Ну и наконец, размещение автоматизации в панели управления с выводом BuildInfo, вывод которого тоже не бесконечен, поэтому, чтобы увидеть аргументы, с которыми по кнопке запускается та или иная программ, лучше иметь короткие имена блоков.

.
Для визуализации процесса можно перед вызовом через панель управления настроек LCD, в котором хранится код, переключиться на вид от третьего лица и отрегулировать прозрачность панели управления так, чтобы было видно, что происходит.

Для автоматической регулировки подвески этот метод годится, а вот для автоматизации “полицейского разворота” – нет. Там программу приходится вызывается по цифровой кнопке из настроек кокпита, а не из контрольной панели. Здесь как раз и может пригодиться дополнительный отладочный LCD на который будет выводиться диагностика ошибок, которых, поверьте, будет немало особенно по началу.

Производственный процесс

Originally posted by Общее замечание:

Далее предполагается, что вы в, общих чертах, ознакомились с авторским руководством по Easy Automatiotion 2.0, т.к. ниже будут описаны особенности кодирования, на которых автор не обратил внимание, посчитав их очевидными, либо недостаточно расставил акценты. Руководство, как и сам интерпретатор – своеобразные, но в любом случае автору конкретный респект за +2000 строк кода и сопровождение скрипта.

Все программы автоматизации, а вернее, подпрограммы EA2 располагаются в блоке “Свои данные” LCD дисплея, имя которого указывается в качестве параметра при запуске ПБ в котором размещен скрипт. Поэтому для того чтобы разместить там код, необходимо:

  1. вызвать на экран общую панель управления по Ctrl+K
  2. найти в списке блоков нужный LCD и нажать “Свои данные”

В открывшемся окне, которое трудно назвать редактором кода, нужно разместить:

  1. блок @Variables (см. ниже) в котором, если необходимо, будут храниться общие настройки
  2. прочие подпрограммы или, как я их называю, @-блоки в которых размещается код автоматизации EA2
  3. комментарии – любая строка, начинающаяся с символа * (звездочка), комментарии не переносятся, каждая новая строка также начинается со *

В итоге должно получить примерно следующее

.

Originally posted by Важно:

Сразу обратите внимание на {} (фигурные скобки). В одной строке с именем @-блока открывающую скобку нужно располагать в конце строки, во всех остальных случаях каждая фигурная скобка должны быть оформлена отдельной строкой

Далее, все инструкции интерпретатора должны начинаться с заглавной буквы и написаны в точности так, как это указано в авторском руководстве. Т.е. @Variables, но не @variables или @VARIABLES, но, например, можно написать Show properties, а можно Show Properties и это сработает.

Названия @-блоков произвольные, но в них нельзя использовать спецсимволы, а обращаться к ним при запуске через в поле “аргумент” ПБ нужно в точности как написано: LCD Code(police_turn) – символ @ при обращении использовать не надо, но не LCD Code(POLICE_tutn) тоже и для названия блока LCD – именно LCD Code, но не LCD code(police_turn).

В общем, большинство ошибок по началу будет связано именно с написанием команд и имен блоков, к которым, как и в случае с LCD Code, нужно будет обращаться с учетом регистра. Поэтому если вы собираетесь заняться автоматизацией с помощью EA2, то следует пересмотреть свое отношение к именованию блоков.

Если колесо у вас названо по умолчанию в русской локализации, типа “Колесо с подвеской 3х3 (правое)” то вот так и придется писать в коде, если нужно будет узнать его установки. Мало того, что это длинно и придется переключаться между раскладками клавиатуры, но если вы собираетесь выкладывать свой крафт в Steam, то это еще и не понятно для большинства игроков. В списке блоков панели управления напротив такого колеса будет стоять соответствующая иконка, а вот в коде ее не будет.

Полицейский разворот

Поскольку руководство называется “практическим”, то и дальнейшее описание пойдет на примере автоматизации “полицейского разворота” ровера при помощи гироскопов, точнее резкой смены направления движения на противоположное, которое называют еще “реверсным” или “ретро” разворотом.

Но в начале о двух самых важных командах, без которых автоматизация в SE была бы сильно ограниченной, поскольку данные Official Guide: Programmable block – официального руководства, где описаны свойства и действия большинства игровых блоков в SE, сильно устарели.

Originally posted by Важно!:

Show properties of <Имя блока> – вывод всех доступных настроек блока
Show actions of <Имя блока> – вывод всех доступных действий, которые можно выполнить

Обе эти команды выводят на экран, связанного с ПБ экрана, перечень свойств и действий, доступных для определенного блока. Например, чтобы узнать, что можно вытащить по гироскопам M-577, достаточно достаточно выполнить простую программу из одной строки:

@test { Show properties of Gyroscope }

В авторском руководстве показан вывод на ЖК-экран, но проще смотреть результат прямо в настройках LCD Code в поле “Редактировать” т.к. оттуда легко скопировать нужное свойство и вставить его в поле “Свои данные”.

.
В этом списке указано все настройки, которые можно видеть в панели управления гироскопом, которые можно считать или изменить.

.

Собственно, Easy Automatition 2.0 и позволяет это сделать для любого блока – в этом суть автоматизации с его помощью.

Originally posted by Внимание:

С WeaponCore EA2 не работает, он может обращаться только к свойствам и действиям ванильных блоков.

Вернемся к задаче:

Для того, чтобы резко и безопасно развернуть ровер на 180 градусов потребуется:

  • уменьшить трение колес до 0
  • включить перехват управления гироскопами по рысканью на заданное время
  • восстановить сцепление колес с грунтом, чтобы можно было затормозить, нажав “P”

Все, кроме последнего – нажатия на тормоз, можно сделать при помощи EA2. Код полный автоматизации (выглядит несколько устрашающе, но это исключительно из-за требований к оформлению кода – “одна фигурная скобка на одной строке”):

* gyar – сила перехвата ускорения по рысканью * wfric – начальная установка трения колес -1 * wturn – время разворота в мс @Variables { gyaw = 10.0 wfric = 99.0 wturn = 3000 } @friction_down { DecreaseFriction (APC, Wheels) if Friction of Wheel 5×5 FL > 0.0 { @friction_down } } @friction_up { IncreaseFriction (APC, Wheels) if Friction of Wheel 5×5 FL < wfric { @friction_up } } @yaw_up { IncreaseYaw (APC, gyroscope) if Yaw of (APC, gyroscope) << gyaw { @yaw_up } } @yaw_down { DecreaseYaw (APC, gyroscope) if Yaw of (APC, gyroscope) > 0.0 { @yaw_down } } @police_turn { * если перехват не установлен руками If Override of Gyroscope = False { * увеличиваем перехват по крену @yaw_up * уменьшаем трение до 0 @friction_down * включаем перехват гироскопами Override (APC, gyroscope) * на заданное в переменной wturn время Delay wturn * выключаем перехват гироскопами Override (APC, gyroscope) * устанавливаем значение перехвата в 0 @yaw_down * восстанавливаем трение @friction_up } }

Боевое программирование

Название раздела несколько высокопарное, но между тем кто из вас задавался вопросом “а что будет с автоматизацией на таймерах, если один из них повредится во время боя или просто при столкновении с препятствием?” В случае с M-577 при попытке сложить турель, ее, как минимум, заклинит, а как максимум – поймаем clang.

Так что автоматизировать боевые крафты нужно с учетом возможных потерь и EA2 позволяет это сделать, хотя это и не описано явно у автора. Итак, обратите внимание на два @-блока кода:

@friction_up { IncreaseFriction (APC, Wheels) if Friction of Wheel 5×5 FL < wfric { @friction_up } } @yaw_up { IncreaseYaw (APC, gyroscope) if Yaw of (APC, gyroscope) << gyaw { @yaw_up } }

Первый реализует неявный цикл увеличения высоты подвески до заданного значения (это из другой автоматизации M-577), а второй увеличивает значение перехвата гироскопом по рысканью. Первый написан неправильно, а второй правильно и вот почему.

Поскольку настройка подвески всех колес M-577 одинаковая, то я изменяю ее, основываясь на текущем значении левого переднего колеса и если его оторвет, то скрипт вылетит с ошибкой и высота подвески остальных колес не изменится.

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

В этом и заключается “боевое программирование”. Есть еще одна интересная особенность связанная с обращением по имени блока. Если вы посмотрите мой крафт, то сможете убедиться, что все гироскопы в нем названы одинаково – “Gyroscope” без традиционной нумерации после имени блока, а теперь вернемся к коду “полицейского разворота” и обратим внимание на следующую строку блока @police_turn:

If Override of Gyroscope = False

Здесь запрашивается текущее значение установки перехвата первого блока с именем Gyroscope, а поскольку все гироскопы названы одинаково, то до тех пор, пока будет цел хотя бы один гироскоп условие будет работать. Это, по сути, неявное обращение к группе однотипных блоков.

Кино и немцы

В смысле “Логика и циклы”, дальше вы поймете, почему раздел назван именно так. 🙂

В EA2 присутствует традиционная логика if-else if-else, которая является основой любой автоматизации и которая достаточно подробно описано в руководстве. Чего там не написано, так это то, что она не всегда работает в для очевидных, казалось бы вещей.

Есть в EA2 полезная команда – развернуть ротор на заданный угол с заданной скоростью: Rotate <MyRotor> то <NN> at <SS>, где MyRotor – имя блока ротора, который нужно повернуть, NN – угол на который нужно повернуть и SS – скорость с которой поворачивать. Еще есть практически та же команда ShortRotate – повернуть по кратчайшему пути.

Все вроде просто и код типа

* повернуть ротор азимута турели по кратчайшему пути до нуля ShortRotate Rotor Azimuth to 0 at 5 * приостановить программу до тех пор пока угол 0 не достигнут When Current angle Rotor Azimuth = 0 * задвинуть поршень турели Retract Piston Gun

кажется, на первый взгляд, вполне нормальным и логичным, но только не для SE. Недаром у ротора есть такая установка, как “тормозной момент”, которая влияет на скорость остановки.

Так вот, в зависимости от массы установленного на роторе грида и гравитации планеты, точный 0 может быть просто не достигнут, а его значение после выполнения поворота, будет близким к нулю, например, 0.0345, но не 0. И это справедливо не только для ротора.

Поэтому @-блок просто зависнет, а с ней и ПБ и вся завязанная на него автоматизация. Чтобы этого избежать, нужно использовать сравнение с 10-й точкой When Current angle Rotor Azimuth = 0.0, но еще лучше сравнивать либо с близким, заведомо превышающим точное значение, числом либо вообще, использовать неравенство: When Current angle Rotor Azimuth > 0.0, но как оказалось, в случае с ротором и это еще не все. Рабочее решение с анализом угла поворота есть в блоке @gun_trigger моего крафта. Здесь речь не об этом…

… а о том, что явных циклов, к сожалению, в EA2 на момент написания этого руководства нет. Ни условного while, ни итерационного for, а между тем они крайне нужны для установки “ползунковых” значений большинства блоков.

По непонятной мне причине, в SE для того же гироскопа нет команды “установить значение перехвата по рысканью = 100%”, а есть только то, что можно увидеть в меню блока, в процессе перетаскивания его из панели инструментов, вызываемой по “G”, на цифровую панель управления кокпита, а именно “уменьшить перехват” или “увеличить перехват” на неизвестную заранее величину.

Для гироскопа опытным путем это значение равно 5%, а для подвески – 6 см. Поэтому цикл пришлось изобретать на ходу и выглядит он просто как в таймере – замыкание выполнения на себя

@yaw_down { * уменьшить перехват по рысканью на 5% DecreaseYaw (APC, gyroscope) * до 0 if Yaw of (APC, gyroscope) > 0.0 { * замкнуть выполнение на себя @yaw_down } }

Конечно, подобный метод небезопасен и может вызвать зависание, если условие подобрано неверно, но другого пути организовать цикл я не нашел. When здесь не применить, потому что в отличии от запуска вращения ротора, уменьшение перехвата – разовая команда, которую нужно либо тупо повторить определенное число раз, либо выполнить в цикле. Поскольку начальные настройки зависят от игрока и могут быть любыми – повторение, хоть и безопаснее, но не является гарантией достижения результата. Вот такое кино…

Ошибки молодости

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

Диагностика ошибок в EA2 сводится к указанию строки, в которой она обнаружена и все, причем отсчет ведется от начала @-блока, в котором произошла ошибка часто без указания сбойного фрагмента кода. Так что приходится вручную каждый отсчитывать количество строк от начала блока, чтобы найти эту строку.

.
И это при том, что функция поиска в самом редакторе кода отсутствует как класс. Так что придется сначала глазами найти сбойный @-блок, а затем отсчитать от его начала указанное количество строк и попытаться разобраться в чем дело.

Если же при построчном разборе кода ЕА2 не находит того, что относится к интерпретатору, то управление просто передается в игровой код SE, обрабатывающий ПБ и тот рушится с конкретной “портянкой” И “это фиаско, братан!” – после исправления ошибки придется перекомпилировать скрипт, чтобы ПБ снова заработал.

.
Часто диагностика просто “молчит”, но при этом ничего не работает. Обычно это связано с расстановкой скобок “{}()”, стоит по привычке указать открывающую скобку в конце If или заключить условие в “()”, чтобы получить в ответ пустую диагностику и легкое недоумение – “все же только что работало!”.

Добавьте сюда невозможность отката в редакторе и игнорирование закрытие окна по [ x ] в правом верхнем углу, в надежде предотвратить запись только что произведенных изменений и вы познаете дзен кодирования в среде SE, но третьего не дано – вы либо пишите код, либо его не пишите.

Чтобы узнать, работает ли блок вообще или безнадежно висит просто попробуйте обратиться к несуществующему @-блоку. Если вы увидите сообщение о том что блок не найден, значит ПБ работает, а если пустую диагностику, значит требуется перекомпиляция кода скрипта EA2.

.
И последнее. Внутренняя команда определения положения поршня “Current position” зависит от локализации

@variables { piston = Current position of MyPiston } @show { WriteNew to DBG Code = “piston” }

Вызовет ошибку “Поршень does not have a “Current position” value, в русской версии игры будет работать

@variables { piston = Текущая позиция of MyPiston } @show { WriteNew to DBG Code = “piston” }

При этом аналогичный запрос “Current angle of MyRotor” работает нормально.Возможно, автор скрипта поправит это в следующих версиях. Я оставил запрос в комментариях под авторским руководством, но пока придется каждый раз указывать полностью имя блока в If, что неудобно при необходимости переименовать поршень или при случайном изменении его имени.

SteamSolo.com