Найти тему

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

Оглавление
Видео с демонстрацией работы скрипта в конце публикации.

В прошлой статье мы научились автоматизировать работу поршня. Самое время применить знания на практике.

Вы пробовали делать выдвижное шасси корабля на поршнях? Поймав под "ногой" неровность рельефа, поршень начинает поднимать корабль вверх. В итоге, возможность горизонтальной парковки ограничивается только лишь ровными поверхностями ледяных озер. Либо корабль будет стоять под наклоном. И, если для маленьких скаутов это не важно, то для больших кораблей-баз... я бы сказал: "не серьезно"!

В этой статье создадим скрипт, позволяющий ровно парковать корабль, не зависимо от формы рельефа под ним.

Постановка задачи

По команде от игрока, скрипт должен выдать команду на выдвижение всем поршням. Далее, каждый тик программа контролирует свойство "Готово к стыковке" посадочного шасси, расположенного на поршне. Как только это свойство станет истинным, необходимо остановить выдвижение поршня и примагнитить шасси к земле. Движение остальных поршней должно продолжаться.

По команде игрока на поднятие шасси, скрипт "отмагнитит" все "ноги" и поднимет их поршнями.

Мне очень не понравилось то, как выглядит код в прошлых статьях, поэтому тут он будет в виде картинки. А в конце статьи будет ссылка на GitHub, от куда вы сможете его скопировать.

Листинг программы

-2
-3
-4

Ключевое слово struct

C-шарп позволяет объединять любые типы данных в структуры. Например:

struct Structure
{
public int A;
public bool B;
}

Structure myStructure;

Создаем переменную myStructure типа Structure. В дальнейшем, после создания этой переменной, мы сможем обращаться к её полям по типу: myStructure.A = 10; или myStructure.B = true;

Опоры

В нашем случае нам важно, чтобы точно соблюдалась пара поршень-шасси. Иначе, получив сигнал о достижении земли, может случиться, что скрипт остановит не тот поршень. Поэтому создадим такую пару в виде структуры LandingSupport. Для простоты будем называть такую пару: "Опора".

private struct LandingSupport
{
// Ссылка на блок поршень
public IMyPistonBase Piston;
// Ссылка на блок шасси
public IMyLandingGear LandingGear;
}

Теперь все опоры нашего корабля соберем в список:

private readonly List<LandingSupport> Supports = new List<LandingSupport>();

В теле метода Program() формируем пару поршень-шасси и добавляем её в список опор:

Supports.Add(new LandingSupport() {
Piston = GridTerminalSystem.GetBlockWithName("Поршень 1") as IMyPistonBase,
LandingGear =
GridTerminalSystem.GetBlockWithName("Посадочные шасси 1") as IMyLandingGear
});

Повторяем это действие для всех опор корабля. Их количество должно быть от 1 до... честно говоря, я не знаю, чем ограничен размер списка. Наверное, оперативной памятью компьютера.

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

for (int i = 0; i < Supports.Count; i++)
{
// Устанавливаем максимально возможную дистанцию выдвижения поршня опоры на 10 м
Supports[i].Piston.MaxLimit = 10;
// Устанавливаем минимальную дистанцию для сложенного поршня, 0 м
Supports[i].Piston.MinLimit = 0;
// Принудительно втягиваем все поршни, установив им отрицательную скорость
Supports[i].Piston.Velocity = -PISTON_VELOCITY;
// Отключаем у шасси автозацеп
Supports[i].LandingGear.AutoLock = false;
// Отключаем у шасси режим парковки по нажатии игроком кнопки "Р"
Supports[i].LandingGear.IsParkingEnabled = false;

// Выводим в терминале название поршня, входящего в опору
Echo(Supports[i].Piston.DisplayNameText);
// Выводим в терминале название шасси, входящего в опору
Echo(Supports[i].LandingGear.DisplayNameText);
}

Echo()

Эта функция позволяет выводить текст прямо в терминал. Удобно для дебага скрипта. Синтаксис:

Echo(string);

Счетчик SupportsReadyCounter

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

case "DOWN"

Как только игрок подал Программируемому блоку команду на выдвижение опор, скрипт обнуляет счетчик SupportsReadyCounter и в цикле foreach перебирает все опоры.

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

Runtime.UpdateFrequency = UpdateFrequency.Update1;

case UpdateType.Update1

Каждый тик симуляции скрипт проверяет свойство LockMode шасси, входящей в опору. Истинное значение условия
support.LandingGear.LockMode == LandingGearMode.ReadyToLock
говорит о том, что шасси достигло земли. Поэтому мы останавливаем поршень:

support.Piston.Velocity = 0;

примагничиваем шасси:

support.LandingGear.Lock();

и увеличиваем счетчик завершивших работу опор:

SupportsReadyCounter++;

Также, каждый тик мы проверяем, что все опоры закончили выдвижение. И, если это так, останавливаем скрипт командой:

Runtime.UpdateFrequency = UpdateFrequency.None;

case "UP"

Этот блок кода поднимает опоры. Тут все просто: размагнитил шасси, задал поршням отрицательную скорость. Контролировать положения не надо - поршень сложится и останется на месте самостоятельно.

Заключение

В этом скрипте есть одна недоработка. Бывает, что магнитное шасси попадает на воксель под большим углом и не выдает сигнал ReadyToLock. Однако, скрипт будет упорно ждать, пока все шасси станут замкнуты. Для этого в скрипт необходимо ввести таймаут работы. Пока что не будем этим заниматься, есть дела поинтереснее.

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

Ссылка на скрипт на GitHub.

Если было не удобно читать код с картинки, сообщите мне в комментариях.

#csharp #spaceengineers