Найти в Дзене

Space Engineers - автоматическое управление поршнем и лампой

(В конце статьи демонстрационное видео) В прошлой статье мы научились получать ссылку на блок, расположенный на гриде. Теперь же, в целях изучения новых возможностей управления блоками, немного доработаем скрипт. Задача: при нажатии игроком на кнопку 2 кокпита, поршень должен выдвинуться до своего максимального лимита, а затем задвинуться обратно. Для наглядности добавим на наш грид красную лампу. Она будет включаться во время движения поршня и отключаться, при возврате поршня в исходное, сложенное положение. Доработаем код из прошлой статьи. // Константа, хранящая скорость выдвижения поршня
private const float PISTON_VELOCITY = -5;
// Создаем переменную Piston типа IMyPistonBase
private readonly IMyPistonBase Piston;
// В этой переменной будем хранить ссылку на лампу
private readonly IMyLightingBlock Lamp;
public Program()
{
// Скрипт не будет выполнять Main() циклично. Только по команде игрока.
R
Оглавление

(В конце статьи демонстрационное видео)

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

Задача: при нажатии игроком на кнопку 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 до двух условий:

  1. case UpdateType.Trigger: - в нём будут обрабатываться "ручные" команды, пришедшие от игрока;
  2. case UpdateType.Update1: - в него скрипт заходит каждый тик и проверяет положение поршня, пока мы это не отменим.

UpdateType.Trigger

Тут в блоке switch-case скрипт проверяет значение аргумента, переданное игроком во время нажатия на кнопку кокпита. Обработку аргумента "TEST" мы рассмотрели в прошлой статье. Теперь же добавился аргумент "START", который мы заведем на кнопку номер 2.

-2

Как только скрипт увидел совпадение по этому параметру, он изменяет скорость поршня на положительную, начиная его раздвижение. И для наглядности включает. А также, что важно, запускает скрипт на циклическое выполнение метода Main() с частотой 60 tps. И уже на следующем тике игровой симуляции скрипт начнет "заходить" в блок
case UpdateType.Update1.

case UpdateType.Update1

Здесь всё логически просто. Каждый тик отслеживаем положение штока поршня. Если он достиг лимита на выдвижение (10 м в нашем примере), то меняем ему скорость на отрицательную. А константа PISTON_VELOCITY, как мы помним - отрицательная.

Второе условие
if (Piston.CurrentPosition == Piston.MinLimit)
- условие остановки скрипта. Оно станет истинным, когда поршень сложится до конца.

В демонстрационном видео, в коде есть недочет. В одном из условий атавизмом осталась лишняя проверка. Какая - не скажу. На работу не влияет :)

Увидели лишнюю проверку в условии? Пишите в комментариях.

#spaceengineers #csharp