Signals
You can define signals based on the amount of arguments you want to pass:
import { Node, Signal } from "godot";
import { ExportSignal } from "godot.annotations";
export default class MyNode extends Node {
@ExportSignal()
declare no_arg!: Signal<() => void>;
@ExportSignal()
declare one_arg!: Signal<(param1: string) => void>;
@ExportSignal()
declare two_args!: Signal<(param1: number, param2: string) => void>;
}
Passing Arguments via Signals
When emitting signals, only Godot-native objects (GArray, GDictionary, and primitives) can be passed as valid arguments. Raw TypeScript/JavaScript objects cannot be used directly.
Incorrect Example:
You can use GDictionary.create
/GArray.create
to convert JS objects to their Godot equivalent data structure.
import { GDictionary } from "godot";
this.some_signal.emit(GDictionary.create({ key: "value" })); // ✅ Godot dictionary
Connect and disconnect to a signal programmatically
import { Node, Callable } from "godot";
export default class MyClass extends Node {
_ready() {
// subscribe
this.get_node("Button").pressed.connect(
Callable.create(this, this.handle_onclick),
0,
);
}
handle_onclick() {
// handle the click event
}
_exit_tree() {
// unsubscribe
this.get_node("Button").pressed.disconnect(
Callable.create(this, this.handle_onclick),
);
}
}
NOTE: Please be cautious that
Callable.create(this, this.xxx) === Callable.create(this, this.xxx)
returnsfalse
.
But it's compared internally in C++ to check equality when using them forconnect
anddisconnect
.NOTE:
Callable
does not hold a strong reference onthis
which given as the first parameter. It becomes invalid after the corresponding javascript object is garbage collected.
HOWEVER, it may cause object leaks ifthis
is captured in a lambda function. So avoid coding in this wayCallable.create(this, () => this.xxx())
.
Await a Signal
A Signal
can be awaitable in javascript by calling as_promise()
:
import { Node, Signal1 } from "godot";
import { signal } from "godot.annotations";
class ExampleClass extends Node {
@signal()
declare test_signal!: Signal1<number>;
_ready() {
test();
}
async test() {
console.log("before signal emit");
// result is 123
const result = await this.test_signal.as_promise();
console.log("after signal emit", result);
}
emit_somehow() {
this.test_signal.emit(123);
}
}