Особенности

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

Type conversion and casting

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

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

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

Для этого в C# имеются различные опции.

Casting and Type Checking

Throws InvalidCastException if the returned node cannot be cast to Sprite. You would use it instead of the as operator if you are pretty sure it won’t fail.

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

Using the AS operator

The as operator returns null if the node cannot be cast to Sprite, and for that reason, it cannot be used with value types.

Sprite mySprite = GetNode("MySprite") as Sprite;
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);

Using the generic methods

Generic methods are also provided to make this type conversion transparent.

GetNode<T>() casts the node before returning it. It will throw an InvalidCastException if the node cannot be cast to the desired type.

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

GetNodeOrNull<T>() uses the as operator and will return null if the node cannot be cast to the desired type.

Sprite mySprite = GetNodeOrNull<Sprite>("MySprite");
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);

Type checking using the IS operator

To check if the node can be cast to Sprite, you can use the is operator. The is operator returns false if the node cannot be cast to Sprite, otherwise it returns true.

if (GetNode("MySprite") is Sprite)
{
    // Yup, it's a sprite!
}

For more advanced type checking, you can look into Pattern Matching.

C# signals

For a complete C# example, see the Handling a signal section in the step by step Написание скриптов tutorial.

Declaring a signal in C# is done with the [Signal] attribute on a delegate.

[Signal]
delegate void MySignal();

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

These signals can then be connected either in the editor or from code with 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");
}

Emitting signals is done with the EmitSignal method.

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

Notice that you can always reference a signal name with the nameof keyword (applied on the delegate itself).

It is possible to bind values when establishing a connection by passing an object array.

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 });
}

Signals support parameters and bound values of all the built-in types and Classes derived from Godot.Object. Consequently, any Node or Reference will be compatible automatically, but custom data objects will need to extend from Godot.Object or one of its subclasses.

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

Finally, signals can be created by calling AddUserSignal, but be aware that it should be executed before any use of said signals (with Connect or EmitSignal).

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