ECMAScript
ECMAScript copied to clipboard
cannot read property 'emit_signal' of null when emitting a custom signal
Hello, I've having an issue about emitting the custom signal, I think it's broken. The built-in signal works just fine, but the custom are just having an issue.
This is my code:
// UIPause.tsx
import { signal } from "../../decorators";
export default class UIPause extends godot.Control {
@signal static readonly OnContinue: string;
@signal static readonly OnExit: string;
private continueButton: godot.Button;
private exitButton: godot.Button;
public override _ready(): void {
this.continueButton = this.get_node<godot.Button>('ButtonContainer/Continue');
this.exitButton = this.get_node<godot.Button>('ButtonContainer/Exit');
this.continueButton.connect('pressed', this.onContinuePressed);
this.exitButton.connect('pressed', this.onExitPressed);
}
private onContinuePressed(): void {
godot.print('Continue') // works fine, prints Continue
this.emit_signal("OnContinue"); // throws an error
}
private onExitPressed(): void {
this.emit_signal("OnExit"); // also throws an error
}
}
// World.tsx
import CameraControl from "../actors/CameraControl";
import Player from "../actors/Player";
import Scene from "../ecs/Scene";
import UIPause from "../ui/UIPause";
export default class World extends Scene {
private player: Player;
private camera: CameraControl;
private pauseLayer: UIPause;
constructor() {
super();
}
public override initialize(): void {
/** Snip */
}
// Will Run after the initialize method
public override ready(): void {
this.camera.setTarget(this.player.Body);
// Connecting all of the Signals
this.pauseLayer.connect('OnContinue', this.onContinuePlaying);
this.pauseLayer.connect('OnExit', this.onExitMe);
}
public override _input(event: godot.InputEvent): void {
/** Snip */
}
// Won't be called
public onContinuePlaying(): void {
this.player.active = true;
this.pauseLayer.visible = false;
}
// Wont be called
public onExitMe(): void {
this.get_tree().quit();
}
}
May or may not help, but sometimes putting @gdclass
on your class can help when using decorators.
May or may not help, but sometimes putting
@gdclass
on your class can help when using decorators.
It doesn't work too, but I found a workaround and I don't know why this works, but it shouldn't be this way too.
public override _ready(): void {
this.continueButton = this.get_node<godot.Button>('ButtonContainer/Continue');
this.exitButton = this.get_node<godot.Button>('ButtonContainer/Exit');
this.continueButton.connect('pressed', () => {
this.emit_signal("OnContinue");
});
// It also works with string method
this.exitButton.connect('pressed', () => {
this.emit_signal("OnExit");
});
}
It works with Lambda or strings instead, I don't know why but it works, they should better make a custom error for that instead of a cryptic message. I will keep the issue open from now on.
Ohhh...
This is a thing with basic JS.
When passing a method to a function as a callback, the parent scope or this
is reset to the scope of the function that calls it (or null, because native function don't have scope.) due to the fact that it is being separated from the parent, as your passing the function, not the parent, and the function does not contain any information about the parent. Lambdas fix this problem by automatically .bind()
ing the function to the current this
scope.
You can change your connect
to
this.connect("pressed", this.onPressed.bind(this))
or the method declaration to
class MyClass {
onPressed: Function = () => {
...
}
}
(also the errors are just piped from JS, they can't change it without rewriting the compliler)