(В конце статьи демонстрационное видео)
В прошлой статье мы научились получать ссылку на блок, расположенный на гриде. Теперь же, в целях изучения новых возможностей управления блоками, немного доработаем скрипт.
Задача: при нажатии игроком на кнопку 2 кокпита, поршень должен выдвинуться до своего максимального лимита, а затем задвинуться обратно.
Для наглядности добавим на наш грид красную лампу. Она будет включаться во время движения поршня и отключаться, при возврате поршня в исходное, сложенное положение.
Доработаем код из прошлой статьи.
// Константа, хранящая скорость выдвижения поршня
private const float PISTON_VELOCITY = -5;
// Создаем переменную Piston типа IMyPistonBase
private readonly IMyPistonBase Piston;
// В этой переменной будем хранить ссылку на лампу
private readonly IMyLightingBlock Lamp;
public Program()
{
// Скрипт не будет выполнять Main() циклично. Только по команде игрока.
Runtime.UpdateFrequency = UpdateFrequency.None;
// Получаем ссылку на поршень по имени "Поршень"
Piston = GridTerminalSystem.GetBlockWithName("Поршень") as IMyPistonBase;
// Устанавливаем лимит задвижения поршня в 0 м.
// Можно сделать и руками в терминале, но зачем каждый раз проверять настройки?
Piston.MinLimit = 0;
// Лимит выдвижения поршня ставим на максимум: 10 м
Piston.MaxLimit = 10;
// Принудительно задвигаем поршень со скоростью PISTON_VELOCITY.
// Отрицательное значение - задвижение поршня, положительное - выдвижение
Piston.Velocity = PISTON_VELOCITY;
// Получаем ссылку на лампу по имени "Лампа"
Lamp = GridTerminalSystem.GetBlockWithName("Лампа") as IMyLightingBlock;
// Принудительно отключаем лампу
Lamp.Enabled = false;
}
public void Main(string argument, UpdateType updateSource)
{
switch (updateSource)
{
case UpdateType.Trigger:
switch (argument)
{
case "TEST":
// Меняем скорость поршня на противоположную, т.е. выдвигаем/задвигаем
Piston.Velocity = -Piston.Velocity;
break;
case "START":
// Выдвигаем поршень
Piston.Velocity = -PISTON_VELOCITY;
// При получении команды с параметром START, скрипт будет выполнять Main()
// каждый тик (60 раз в секунду) или остановится.
// Цикличное выполнение нужно для контроля положения поршня.
Runtime.UpdateFrequency = UpdateFrequency.Update1;
// Включаем лампу
Lamp.Enabled = true;
break;
}
break;
// Когда скрипт работает 60 раз в секунду, это условие равно истине
case UpdateType.Update1:
// Если поршень выдвинулся на максимальную дистанцию, задвигаем его
if (Piston.CurrentPosition == Piston.MaxLimit) Piston.Velocity = PISTON_VELOCITY;
// Если поршень полностью задвинут, то:
if (Piston.CurrentPosition == Piston.MinLimit)
{
// Останавливаем скрипт до ожидания нового нажатия игроком на кнопки.
Runtime.UpdateFrequency = UpdateFrequency.None;
// Отключаем лампу
Lamp.Enabled = false;
}
break;
}
}
Мы ввели в скрипт константу PISTON_VELOCITY. Константы удобны тем, что её значение указывается только один раз в начале программы. И при возникновении необходимости изменить значение, не надо "бегать" по всему коду.
UpdateFrequency
В коде появилась запись Runtime.UpdateFrequency. Она определяет поведение скрипта в отношении метода Main(). Если Runtime.UpdateFrequency = UpdateFrequency.None;
Main() выполняется только при "ручном" вызове игроком, другим блоком или антенной.
Если Runtime.UpdateFrequency = UpdateFrequency.Update1;
Main() выполняется циклически, не блокируя при этом вызовы "ручными" способами.
В Space Engineers существует понятие скорость симуляции: simspeed. Пошло от игроков, поэтому не совсем корректно. Правильнее оперировать частотой симуляции: ticks per second. При нормальной работе компьютера tps ограничено 60 тиками в секунду. UpdateFrequency.Update1 означает, что Main() будет вызывать каждый тик, т.е. 60 раз в секунду.
Нам доступны значения:
- Update1 - каждый тик;
- Update10 - каждый десятый тик;
- Update100 - каждый сотый тик.
На самом деле, для примера достаточно значения Update100, но гулять, так гулять!
Lamp
Здесь всё по аналогии с поршнем. В методе Program() получаем ссылку на блок и сразу отключаем свечение. Кстати, свойство Enabled универсально для всех терминальных блоков в игре. Можете включать и отключать что угодно.
updateSource
Как видите, мы развили блок switch-case до двух условий:
- case UpdateType.Trigger: - в нём будут обрабатываться "ручные" команды, пришедшие от игрока;
- case UpdateType.Update1: - в него скрипт заходит каждый тик и проверяет положение поршня, пока мы это не отменим.
UpdateType.Trigger
Тут в блоке switch-case скрипт проверяет значение аргумента, переданное игроком во время нажатия на кнопку кокпита. Обработку аргумента "TEST" мы рассмотрели в прошлой статье. Теперь же добавился аргумент "START", который мы заведем на кнопку номер 2.
Как только скрипт увидел совпадение по этому параметру, он изменяет скорость поршня на положительную, начиная его раздвижение. И для наглядности включает. А также, что важно, запускает скрипт на циклическое выполнение метода Main() с частотой 60 tps. И уже на следующем тике игровой симуляции скрипт начнет "заходить" в блок
case UpdateType.Update1.
case UpdateType.Update1
Здесь всё логически просто. Каждый тик отслеживаем положение штока поршня. Если он достиг лимита на выдвижение (10 м в нашем примере), то меняем ему скорость на отрицательную. А константа PISTON_VELOCITY, как мы помним - отрицательная.
Второе условие
if (Piston.CurrentPosition == Piston.MinLimit)
- условие остановки скрипта. Оно станет истинным, когда поршень сложится до конца.
В демонстрационном видео, в коде есть недочет. В одном из условий атавизмом осталась лишняя проверка. Какая - не скажу. На работу не влияет :)
Увидели лишнюю проверку в условии? Пишите в комментариях.
#spaceengineers #csharp