기능

이 페이지는 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 연산자 사용하기

노드가 Sprite를 캐스트 하지 않는다면 as 연산자는 null을 반환합니다, 그리고 그 이유에서, 이것이 값 타입과 함께 사용될 수 없습니다.

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

이 시그널들은 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 });
}

시그널은 매개변수를 지원하고, 모든 내장 타입의 값들과 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");
}