Custom signal is not working for me

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By inTech
:warning: Old Version Published before Godot 3 was released.

Hey everyone

I read about signal and I find the concept to be interesting and a good thing to add into my game. I read the tutorial here and followed the code snippet and implant it inside my project.

Instead of giving all my codes (which is a mess), I am just going to show part of the code.


A Label node that will appear when the user pause or lose a game.

extends Label

signal restart_game;

func _ready():
    set_process_input(true);

func _input(event):
    if(event.is_action("ui_accept") && get_tree().is_paused()):
        emit_signal("restart_game");
        get_tree().set_pause(false);

KinematicBody2D node - player

extends KinematicBody2D

var startX = get_pos().x;
var startY = get_pos().y;

func _ready():
    set_process_input(true);
    connect("restart_game", self, "restartGame");

func restartGame():
    print("Restarting game ... ");
    set_pos(Vector2(startX, startY));

    

With this, I am expected to see the player node go back to its original position. I am also expected to see “Restarting game …” in the debugging console but there isn’t.

The Label node is inside another scene where it is instanced inside the main scene. The KinematicBody2D node is also inside yet another scene where it is also instanced inside the main scene. Which mean there is a total of three scenes - level.tscn, player.tscn and pause.tscn.


So I thought the problem might be with the logic of my program so I try to run the following code and I expect an endless prints, but there is nothing in the debugging console.

extends Label

signal restart_game;

func _ready():
    set_process(true);
    set_process_input(true);

func _process(delta):
        emit_signal("restart_game");

func _input(event):
    if(event.is_action("ui_accept") && get_tree().is_paused()):
        get_tree().set_pause(false);

Edited: After some testing, it seem that the emit_signal function works with the following code.

extends Label

signal restart_game;

func _ready():
    set_process(true);
    set_process_input(true);
    connect("restart_game", self, "restartGame");

func _process(delta):
        emit_signal("restart_game");

func _input(event):
    if(event.is_action("ui_accept") && get_tree().is_paused()):
        get_tree().set_pause(false);

func restartGame():
    print("restarting game ... ");

This mean that the emit_signal() function is working as intended but somehow my KinematicBody2D node from another scene cannot receive the signal.

I think that the problem fall within the “connect(“restart_game”, self, “restartGame”);” code. To be more specific, the second argument. I can’t find any documents about connect() function though.

:bust_in_silhouette: Reply From: indicainkwell

Signals are local to an object. So, you’ll need a reference to that Label to connect to the restart_game signal.

For Example:

# ... in KinematicBody2D script

# get reference to label node
var label = get_node("/path/to/label")
# connect restart_game signal to self.restartGame
label.connect("restart_game", self, "restartGame")

Ahh so that is the problem. My mistake for not reading the script on the Reddit post well. So I tried to get a reference to the label node via

onready var PauseNode = get_node("/root/Node/PauseNode/Label");

But the output of print(PauseNode) is [Object:null]. I am expecting something like [Label:UID]. Without getting the right reference, I cannot call for the signal.

onready var MainNode = get_node("/root/Node/");

When printed, it does return [Node:575]. But I can’t seem to get nodes inside instanced scene.

Edited:

I found out the problem. It is because I instanced the player scene before the pause scene. Hence when the player is ready the pause scene nodes is not ready yet. I switch the priority and the reference to the PauseNode is working. However, the PauseNode is also required to call the player node which is not working now.

Is there anyway to get a reference to an object after sometime - wait until all scenes is instanced? I think Timer will work, is there any easier way without adding another Timer node?

Edited (#2):

I fixed this by calling another signal after I loaded all the scenes from a script inside the main scene.

# Load scenes
emit_signal("allScenesLoaded");

Then inside all the nodes that require references to another nodes, I add the below code to _ready() function.

func _ready():
    get_node("/root/Node").connect("allScenesLoaded", self, "connect_Signals");

func connect_Signals():
    pauseNode = get_node("/root/Node/PauseNode/Label");
    print(pauseNode); #pauseNode.connect("restart_game", self, "restartGame");

inTech | 2016-12-16 02:17