How to connect signal to a node outside a scene

Godot 4

Hi! I need to connect a signal to a node that is outside my scene (it’s going to be spawned in the scene). I tried to follow tutorials but I still don’t get it :frowning:

Main Scene

signal track()

func _on_ghost_life_timeout():
	randomize()
	var colectables = [ghost,ghost,ghost,ghost]
	var kinds = colectables[randi()% colectables.size()]
	var spawner = kinds.instantiate()
	var track = randi_range(0,2)
	emit_signal("track")
	spawner.position = Vector2(location_x[track], location_y)
	add_child(spawner)

Spawned object

func _ready():
	scale = Vector2(0.2,0.2)
	var main_scene = get_node("res://scenes/game_ghosthouse.tscn")
	main_scene.track.connect(_move)

func _process(delta):
	scale += Vector2(0.005,0.005)
	_move()

func _move():
	position.y += 0.51

In the second script it says get_node("res://scenes/game_ghosthouse.tscn"). The problem with this is that you’re trying to load the scene file, not the node itself. You can fix this by replacing the entire get_node() call with $path/to/the/node. You can drag the node from the scene tree right into the editor and Godot will generate the node path for you.
The end result should look something like this:

func _ready():
	scale = Vector2(0.2,0.2)
	var main_scene = $/path/to/main_scene
	main_scene.track.connect(_move)
2 Likes

Unfortunetly it’s not working. But I think there might be misunderstanding - node game_ghosthouse is not in the scene tree, I try to signal from game_ghosthouse to the separate node ghost that is not inside game_ghosthouse scene (game_ghosthouse is a root node of a scene)

The thing is, if something is not in the scene tree it’s not really loaded. You can’t signal from a scene, it has to be instantiated first.
You need to connect the signal when you spawn the scene in. For example you could connect the signal right after calling instantiate().

1 Like

Oh, It makes sense, but I thought that I am connecting inside the node that recive a signal, no? game_ghost emites, ghost recives.

You don’t have to be inside the script to connect signals, they mean to update your code like so

func _on_ghost_life_timeout():
	randomize()
	var colectables = [ghost,ghost,ghost,ghost]
	var kinds = colectables[randi()% colectables.size()]
	var spawner = kinds.instantiate()

	# connected immediately after instantiate
	track.connect(spawner._move)

	track.emit()
	var track = randi_range(0,2)
	spawner.position = Vector2(location_x[track], location_y)
	add_child(spawner)

However, your connection function is rather odd, being called in _process means it is run once when something is spawned, and every frame too. If this is just to test, maybe a print() statement would do better.

1 Like

I think I am missing something, I applied your fix but I have got error “Invalid call. Nonexisting function ‘connect’ in base nill”.

It’s not ideal that my implementation is od :sweat_smile: How should I do it correctly then? maybe that would be easier then fixing this mess. I put emiter inside _process because it’s where I am spawning, and I specificly need to let my ghost know on which track it was spawned so I can move it in right direction (object from left track goes to left, right to right side and middle one goes down)

Huh, was the signal “track” deleted?

1 Like

No, it’s still there, first line in the code for game_ghostgame :> signal track() maybe I have got wrong syntax?

1 Like

I am confident that is the correct syntax. You could shorten it to signal track (no parenthesis) since you don’t take any arguments.

I notice you also created a variable var track, this is called shadowing; I’d recommend against it. Is there anywhere else you are modifying track?

1 Like

O I didn’t know about shadowing, thank you! I will avoid it ^^ No I don’t modify track anywhere else, right know whole script looks like this:

extends Node2D

var ghost = preload("res://prefabs/ghost/ghost.tscn")
var coin_01 = preload("res://prefabs/Shooter/shooter_coin_01.tscn")
var coin_05 = preload("res://prefabs/Shooter/shooter_coin_05.tscn")

var location_x = [680,960,1240]
var location_y = 550
@onready var ghost_signal = "res://prefabs/ghost/ghost.tscn"

signal track

func _ready():
	pass


func _process(delta):
	pass


func _on_ghost_life_timeout():
	randomize()
	var colectables = [ghost,ghost,ghost,ghost]
	var kinds = colectables[randi()% colectables.size()]
	var spawner = kinds.instantiate()
	
	track.connect(spawner._move)
	
	var track_choose = randi_range(0,2)
	emit_signal("track")
	spawner.position = Vector2(location_x[track_choose], location_y)
	add_child(spawner)

func _move():
	pass

1 Like

Could you paste the exact error and edit a comment pointing out which line? Such a strange error, I feel there is no way track is nil

I was happy for a moment, but turns out It is still not working but even more XD signal is not sending after I deleted parenthesis, so I thought it works. I have no idea what’s wrong, and I think I need to scrap that and start over XD

Well how are you detecting if the signal is sending? I mentioned it was a strange test before, the _move function happens every frame as-is so a signal would be impossible to recognize as a player/tester

1 Like

Well when the signal is not send the game works, and when the signal is sending game crashes :joy: It’s alright, I give up, I did it via global variable, but thank you very much for your help! I guess I need to figure out how signals work cos It feels like a magic to me still :sweat_smile:

Crashing or entering a stack trace? If the game ever freezes and becomes unresponsive make sure to tab back into the editor, it is probably trying to tell you where an error is with great accuracy.

Game minimazes, It’s still runing in the background, but ghost characters are not shown anymore (they are not spawning I suposse)

1 Like