Up to date
This page is up to date for Godot 4.0
. If you still find outdated information, please open an issue.
C# signals
For a detailed explanation of signals in general, see the Using signals section in the step by step tutorial.
While it is still possible to use signals through the Connect
/Disconnect
API, C# gives us a more idiomatic way to implement the observer pattern.
Signals as C# events
To provide more type-safety, Godot signals are also all available through events. You can handle these events, as any other event, with the +=
and -=
operators.
Timer myTimer = GetNode<Timer>("Timer");
myTimer.Timeout += () => GD.Print("Timeout!");
In addition, you can always access signal names associated with a node type through its nested SignalName
class. This is useful when, for example, you want to await on a signal (see await keyword).
await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
Note
Godot will take care of disconnecting all the signals you connected through events when your nodes are freed. Meaning that: as you don’t need to call Disconnect
on all signals you used Connect
on, you don’t need to -=
all the signals you used +=
on.
Custom signals as C# events
To declare a custom event in your C# script, use the [Signal]
attribute on a public delegate type. Note that the name of this delegate needs to end with EventHandler
.
[Signal]
public delegate void MySignalEventHandler();
[Signal]
public delegate void MySignalWithArgumentEventHandler(string myString);
Once this is done, Godot will create the appropriate events automatically behind the scenes. You can then use said events as you’d do for any other Godot signal. Note that events are named using your delegate’s name minus the final EventHandler
part.
public override void _Ready()
{
MySignal += () => GD.Print("Hello!");
MySignalWithArgument += SayHelloTo;
}
private void SayHelloTo(string name)
{
GD.Print($"Hello {name}!");
}
Warning
If you want to connect to these signals in the editor, you will need to (re)build the project to see them appear.
You can click the Build button in the upper-right corner of the editor to do so.
Signal emission
To emit signals, use the EmitSignal
method. Note that, as for signals defined by the engine, your custom signal names are listed under the nested SignalName
class.
public void MyMethodEmittingSignals()
{
EmitSignal(SignalName.MySignal);
EmitSignal(SignalName.MySignalWithArgument, "World");
}
In contrast with other C# events, you cannot use Invoke
to raise events tied to Godot signals.
Signals support arguments of any Variant-compatible type.
Consequently, any Node
or Reference
will be compatible automatically, but custom data objects will need to inherit from GodotObject
or one of its subclasses.
using Godot;
public partial class DataObject : GodotObject
{
public string MyFirstString { get; set; }
public string MySecondString { get; set; }
}
Bound values
Sometimes you’ll want to bind values to a signal when the connection is established, rather than (or in addition to) when the signal is emitted. To do so, you can use an anonymous function like in the following example.
Here, the Button.Pressed signal do not take any argument. But we want to use the same ModifyValue
for both the “plus” and “minus” buttons. So we bind the modifier value at the time we’re connecting the signals.
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;
}
Signal creation at runtime
Finally, you can create custom signals directly while your game is running. Use the AddUserSignal
method for that. Be aware that it should be executed before any use of said signals (either connecting to them or emitting them). Also, note that signals created this way won’t be visible through the SignalName
nested class.
public override void _Ready()
{
AddUserSignal("MyCustomSignal");
EmitSignal("MyCustomSignal");
}