December 25, 2018

Написание скриптов на C# в Godot. Особенности

На этой странице представлен обзор часто используемых функций C# и Godot, а также как они используются вместе.

Тип преобразования и приведение

C# - это язык со статической типизацией. Поэтому вы не можете делать следующее:

var mySprite = GetNode("MySprite")
mySprite.SetFrame(0)

Метод GetNode() возвращает экземпляр узла (Node). Вы должны явно преобразовать его в требуемый производный тип, в данном случае Sprite.

Для этого у в C# есть множество вариантов.

Преобразование и проверка типов

Выдает InvalidCastException, если возвращаемый узел не может быть приведен к Sprite. Вы бы использовали его вместо оператора as, если уверены, что это не будет ошибкой.

Sprite mySprite = (Sprite)GetNode("MySprite");
mySprite.SetFrame(0);

Использование оператора as

Оператор as возвращает null, если узел не может быть приведен к Sprite, и по этой причине его нельзя использовать с типами значений.

Sprite mySprite = GetNode("MySprite") as Sprite;
// Вызывайте SetFrame() только в том случае, если mySprite не равен null
mySprite?.SetFrame(0);

Использование общих методов

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

GetNode<T>() преобразует узел перед его возвратом. Это вызовет InvalidCastException, если узел не может быть приведен к желаемому типу.

Sprite mySprite = GetNode<Sprite>("MySprite");
mySprite.SetFrame(0);

GetNodeOrNull<T>() использует оператор as и возвращает null, если узел не может быть приведен к нужному типу.

Sprite mySprite = GetNodeOrNull<Sprite>("MySprite");
// Вызывайте SetFrame() только в том случае, если mySprite не равен null
mySprite?.SetFrame(0);

Проверка типа с использованием оператора is

Чтобы проверить, может ли узел быть приведен к Sprite, вы можете использовать оператор is. Оператор is возвращает false, если узел не может быть приведен к Sprite, в противном случае он возвращает true.

if (GetNode("MySprite") is Sprite)
{
    // Ура, это спрайт!
}

Для более сложной проверки типов, вы можете посмотреть Pattern Matching.

Сигналы C#

Полный пример для C# см. в разделе Handling a signal в пошаговом руководстве Написание сценариев (скриптов)

Объявление сигнала в C# выполняется с помощью атрибута [Signal] делегата.

[Signal]
delegate void MySignal();

[Signal]
delegate void MySignalWithArguments(string foo, int bar);

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

public void MyCallback()
{
    GD.Print("My callback!");
}

public void MyCallbackWithArguments(string foo, int bar)
{
    GD.Print("My callback with: ", foo, " and ", bar, "!");
}

public void SomeFunction()
{
    instance.Connect("MySignal", this, "MyCallback");
    instance.Connect(nameof(MySignalWithArguments), this, "MyCallbackWithArguments");
}

Оправка сигналов осуществляется методом EmitSignal.

public void SomeFunction()
{
    EmitSignal(nameof(MySignal));
    EmitSignal("MySignalWithArguments", "hello there", 28);
}

Обратите внимание, что вы всегда можете ссылаться на имя сигнала с ключевым словом nameof (применяется к самому делегату).

При установлении соединения можно связать значения, передав массив объектов.

public int Value { get; private set; } = 0;

private void ModifyValue(int modifier)
{
    Value += modifier;
}

public void SomeFunction()
{
    var plusButton = (Button)GetNode("PlusButton");
    var minusButton = (Button)GetNode("MinusButton");

    plusButton.Connect("pressed", this, "ModifyValue", new object[] { 1 });
    minusButton.Connect("pressed", this, "ModifyValue", new object[] { -1 });
}

Сигналы поддерживают параметры и связанные значения всех встроенных типов (built-in types) и классов, производных от Godot.Object. Следовательно, любой узел (Node) или ссылка (Reference) будут совместимы автоматически, но пользовательские объекты данных должны наследоваться от Godot.Object или одного из его подклассов.

public class DataObject : Godot.Object
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

Наконец, сигналы могут быть созданы путем вызова AddUserSignal, но имейте в виду, что он должен выполняться перед любым использованием указанных сигналов (с Connect или EmitSignal).

public void SomeFunction()
{
    AddUserSignal("MyOtherSignal");
    EmitSignal("MyOtherSignal");
}

Оригинал

Помочь в переводе официальной документации