Найти в Дзене

Space Engineers - разбираемся с работой гироскопов, ориентацией структуры и классами в C#

Демонстрационное видео в конце публикации. В прошлой статье мы написали скрипт, позволяющий автоматизировать выдвижение поршней шасси для удобной посадки корабля. Однако, сам корабль при этом приходилось выравнивать вручную. Поэтому настало время разобраться с работой гироскопов для удержания корабля перпендикулярно вектору гравитации планеты. Но к векторам перейдем позже. Сейчас нам необходимо разобраться с тем, как гироскоп создает момент вращения, что такое "Перехват", а также с понятиями: "крен", "рыскание", "тангаж". Задача: создать скрипт, забирающий себе управление гироскопами и дающий момент вращения вокруг одной из осей. Крен, рыскание, тангаж Тут всё просто. Это название осей, вокруг которых корабль совершает вращение. Наглядно показано на картинке: Не смог удержаться. Все любят зелёных кербонавтов. Roll - крен, yaw - рыскание, pitch - тангаж. Классы в C# Класс является основным понятием в объектно-ориентированном программировании. Внутри себя он описывает какую-либо логику о
Оглавление
Демонстрационное видео в конце публикации.

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

Но к векторам перейдем позже. Сейчас нам необходимо разобраться с тем, как гироскоп создает момент вращения, что такое "Перехват", а также с понятиями: "крен", "рыскание", "тангаж".

Задача: создать скрипт, забирающий себе управление гироскопами и дающий момент вращения вокруг одной из осей.

Крен, рыскание, тангаж

Тут всё просто. Это название осей, вокруг которых корабль совершает вращение. Наглядно показано на картинке:

Не смог удержаться. Все любят зелёных кербонавтов.

-2
Roll - крен, yaw - рыскание, pitch - тангаж.

Классы в C#

Класс является основным понятием в объектно-ориентированном программировании. Внутри себя он описывает какую-либо логику операций, а снаружи программист работает с ним, как с "черным ящиком". Т.е. подает сигналы на входы класса, получает с выходов данные, но не углубляется в понимание того, что со всем этим класс сделал внутри себя.

Пример:

public class MyClass
{
// Метод
public int Sum(int x, int y)
{
return x + y + z;
}

// Свойство
public int z { get; set; }
}

Мы создали класс с именем MyClass и реализовали в нем один метод (функцию) Sum, который складывает переданные ему аргументы x и y, добавляет к ним значение свойства z, а затем возвращает результат сложения.

Теперь мы можем использовать этот класс где-нибудь в коде программы:

// Создаем новый экземпляр класса MyClass, который теперь будет называться Class1 (по аналогии с переменной).
private MyClass Class1 = new MyClass();

// Присваиваем свойству z значение 2
Class1.z = 2;

// Вызываем метод Sum с аргументами 2 и 5, который вернёт результат сложения в переменную result
int result = Class1.Sum(3, 5);

Переменная result в нашем примере станет равна 10. Как видите, нам уже не важно уравнение подсчета суммы внутри класса. Теперь мы работаем с методами и свойствами.

Помните, как в прошлой статье мы использовали структуру? Так вот, структура, по сути своей тоже является классом. Просто разработчики языка добавили некий "синтаксический сахар" для повышения удобства разработки кода. Но всё, что мы сделали, используя структуру, можно было реализовать с помощью класса.

Ориентация структуры в Space Engineers

Очень важная тема, необходимая для написания всех автопилотов!

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

Три из них базовые: forward, right и up. Вектора нормированные (имеют длину, равную единице) и перпендикулярные друг другу. Остальные три: backward, down и left - дополнительные, обратные по направлению базовым.

Базовые вектора показаны на картинке.

-3

В игре есть возможность посмотреть вектора ориентации структуры, установив чекбокс "Показать ориентацию структуры" во вкладке "Инфо" терминала. Как показано на картинке.

-4
Всей структуре присваивается ориентация первого блока, с которого начинается строительство. Или ориентация проектора, с помощью которого производилась "сварка". В моем случае - кокпит - первый блок всего кораблика.

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

Код скрипта

-5
-6
-7

На первой картинке реализованы знакомые нам методы Program() и Main(). А вот вторая и третья картинки посвящены классу GyroClass. Начнем разбор кода с него.

public GyroClass(Program)

Это конструктор класса. Каждый раз, когда в коде мы будем использовать запись
Gyro = new GyroClass(this);
будет выполняться этот метод.

Обратите внимание, что мы с самой первой статьи используем конструктор. Нашли? Это public Program(). В нём же мы создали новый экземпляр класса Gyro.

Т.е. все наши скрипты написаны внутри класса Program, созданным разработчиками игры. С той лишь разницей, что в своем классе мы еще добавили в конструктор аргумент prog типа Program. Это сделано для того, чтобы можно было обращаться к свойству GridTerminalSystem класса MyGridProgram, который реализует любимый всеми Программируемый блок.

Мы сделали это кодом
prog.GridTerminalSystem.GetBlocksOfType(Gyros, filter => filter.CubeGrid == prog.Me.CubeGrid);

Собрали все блоки с типом IMyGyros в список Gyros. Но при этом применили фильтр на принадлежность гироскопа гриду, на котором установлен наш Программируемый блок. То есть, скрипт не будет управлять гироскопами пристыкованных через коннекторы кораблей.

Фильтр реализован через лямбда-выражение. Не буду останавливаться на "лямбдах", т.к. перед этим надо разобраться с "делегатами", а это уже совсем другая история.

internal void Override(bool)

Этот метод управляет свойством "Перехват" гироскопов. Т.е. отключает игрока от управления мышкой вращением корабля при аргументе is_script_controlling, равным true. Также он обнуляет все ранее выставленные скриптом воздействия. Если вызвать метод с аргументом, равным false, управление от скрипта перейдет обратно к игроку.

internal void SetPitchRPM(float)

Метод устанавливает значение RPM на все гироскопы списка Gyros. RPM - rotates per minute - количество оборотов в минуту. То есть, скорость, с которой корабль будет вращаться по оси тангажа.

Методы SetYawRPM (рыскание) и SetRollRPM (крен) аналогичны. Не будем останавливаться на них подробно.

public void Main(string argument, UpdateType updateSource)

Теперь, описав логику работы класса, нужно передавать в него команды управления от игрока, сидящего в кокпите.

В блоке switch-case анализируем аргументы и вызываем соответствующий метод класса Gyro.

Ссылка на код в GitHub.

Спасибо за внимание!

В следующей статье напишем автопилот, выравнивающий корабль перпендикулярно вектору гравитации планеты (#автогоризонт).

П.С. Не стесняйтесь, оставляйте в комментариях свои идеи, которые вы бы хотели реализовать.

#spaceengineers #скрипт #csharp