Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

C# 訊號

完整的 C# 例子請參考按部就班 為場景編寫腳本 教學中的 處理訊號 一節。

雖然仍然可以透過「Connect」/「Disconnect」 API 使用訊號,但 C# 為我們提供了一種更慣用的方法來實作觀察者模式<doc_key_concepts_signals>`。

訊號與屬性

為了提供更多的型別安全性,Godot 訊號也可以透過「事件 <https://learn.microsoft.com/en-us/dotnet/csharp/events-overview>」_ 取得。您可以像處理任何其他事件一樣使用“+=”和“-=”運算符來處理這些事件。

Timer myTimer = GetNode<Timer>("Timer");
myTimer.Timeout += () => GD.Print("Timeout!");

此外,您始終可以透過其巢狀的「SignalName」類別存取與節點型別關聯的訊號名稱。例如,當您想要等待訊號時,這很有用(請參閱:ref:doc_c_sharp_differences_await)。

await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);

備註

當您的節點被釋放時,Godot 將負責斷開您透過事件連接的所有訊號。這意味著:由於您不需要對使用“Connect”的所有訊號呼叫“Disconnect”,因此您不需要對使用“+=”的所有訊號呼叫“-=” ` 上。

自定訊號

若要在 C# 腳本中宣告自訂事件,請在公共委派型別上使用「[Signal]」屬性。請注意,該委派的名稱需要以“EventHandler”結尾。

[Signal]
public delegate void MySignalEventHandler();

[Signal]
public delegate void MySignalWithArgumentEventHandler(string myString);

一旦完成,Godot 將在幕後自動建立適當的事件。然後,您可以像處理任何其他 Godot 訊號一樣使用所述事件。請注意,事件是使用委派名稱減去最後的“EventHandler”部分來命名的。

public override void _Ready()
{
    MySignal += () => GD.Print("Hello!");
    MySignalWithArgument += SayHelloTo;
}

private void SayHelloTo(string name)
{
    GD.Print($"Hello {name}!");
}

警告

如果您想在編輯器中連接到這些訊號,您將需要(重新)建置專案才能看到它們出現。

你可以使用右上角的按鈕來。

訊號

若要發出訊號,請使用“EmitSignal”方法。請注意,對於引擎定義的訊號,您的自訂訊號名稱會列在巢狀的“SignalName”類別下。

public void MyMethodEmittingSignals()
{
    EmitSignal(SignalName.MySignal);
    EmitSignal(SignalName.MySignalWithArgument, "World");
}

與其他 C# 事件相比,您不能使用「Invoke」來引發與 Godot 訊號相關的事件。

訊號支援任何與變體相容的 <doc_c_sharp_variant>` 型別的參數。

因此,任何「Node」或「Reference」都會自動相容,但自訂資料物件需要從「GodotObject」或其子類別別之一繼承。

using Godot;

public partial class DataObject : GodotObject
{
    public string MyFirstString { get; set; }
    public string MySecondString { get; set; }
}

列舉值

有時,您需要在建立連線時將值綁定到訊號,而不是在發出訊號時(或除此之外)。為此,您可以使用匿名函式,如下例所示。

這裡,Button.Pressed <class_BaseButton_signal_pressed>` 訊號不帶任何參數。但我們希望對「加號」和「減號」按鈕使用相同的「ModifyValue」 。因此,我們在連接訊號時綁定修飾符值。

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

public override void _Ready()
{
    Button plusButton = GetNode<Button>("PlusButton");
    plusButton.Pressed += () => ModifyValue(1);

    Button minusButton = GetNode<Button>("MinusButton");
    minusButton.Pressed += () => ModifyValue(-1);
}

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

運作時建立訊號

最後,您可以在遊戲運作時直接建立自訂訊號。為此,請使用“AddUserSignal”方法。請注意,應在使用所述訊號(連接到它們或發出它們)之前執行它。另請注意,以這種方式建立的訊號將不會透過「SignalName」巢狀類別可見。

public override void _Ready()
{
    AddUserSignal("MyCustomSignal");
    EmitSignal("MyCustomSignal");
}