기능

이 페이지는 C#과 Godot에서 일반적으로 사용되는 기능과 어떻게 이 둘이 함께 사용되는 지에 대한 개요입니다.

형 변환(Type conversion)과 캐스팅(casting)

C#은 정적으로 타입형 언어입니다. 그러므로 다음을 할 수 없습니다:

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

Node 인스턴스를 반환하는 GetNode() 메서드. Sprite의 경우, 원하는 파생 타입을 명시적으로 변환해야 합니다.

이를 위해, C#에서는 다양한 설정이 있습니다.

캐스트(Cast)와 타입 체크(Type Check)하기

반환된 노드를 Sprite로 캐스트 할 수 없는 경우 InvalidCastException을 발생시킵니다. 실패하지 않는다고 확신하면 as 연산자 대신에 그것을 사용할 것입니다.

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

AS 연산자 사용하기

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

일반 메서드 사용하기

일반 메서드는 이 타입 변환을 투명하게 만들기 위해 제공됩니다.

GetNode<T>()은 반환하기 전에 노드를 캐스트 합니다. 노드가 원하는 타입으로 캐스트 되지 않는다면 InvalidCastException을 발생시킵니다.

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

GetNodeOrNull<T>()as 연산자를 사용하고 노드가 원하는 타입으로 캐스트 되지 않는다면 null을 반환합니다.

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

IS 연산자를 사용하여 타입 체크하기

노드가 Sprite로 캐스트 되도록 체크하기 위해, is 연산자를 사용할 수 있습니다. Sprite가 캐스트 되지 않는다면 is 연산자는 거짓을 반환하고, 그렇지 않으면 참을 반환합니다.

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

더 많은 고급 타입 체크하기의 경우, 패턴 일치에서 찾아볼 수 있습니다.

C# 시그널

완전한 C# 예제를 위해, 단계별 스크립팅(Scripting) 튜토리얼에서 시그널 다루기를 참고하세요.

C#에서 시그널 선언은 델리게이트(delegate)에서 [Signal] 속성으로 됩니다.

[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. If you want to connect a signal in the editor, you need to (re)build the project assemblies to see the new signal. This build can be manually triggered by clicking the “Build” button at the top right corner of the editor window.

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

시그널은 매개변수를 지원하고, 모든 내장 타입의 값들과 Godot.Object에서 파생된 클래스들을 묶습니다. 결과적으로, 모든 NodeReference는 자동으로 호환될 것이지만, 맞춤 데이터 객체는 Godot.Object나 그 하위 클래스에서 확장해야 할 것입니다.

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

마침내, 시그널은 AddUserSignal로 호출하는 것으로 생성될 수 있지만, 시그널을 사용하기 전에 실행되어야 한다는 것을 명심하세요 (ConnectEmitSignal로 말이죠).

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