Link signals from scenes loaded after main scene

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Izaro

Hello everyone!

In my very small game, each level can essentially stand on its own. I’m now trying to make a main scene to be able to switch between them.
The method I chose for this is to emit a signal after each level is completed and then load the next level when the main scene receives said signal.
My problem so far is that I’m not able to get the signal from the loaded scenes to the main scene. I’ve found some posts where the solution somehow is to connect them via <emitting_node>.connect("signal_name", <target_node>, "target_method_name"),
but if I do that I always get the error: "Attempt to call function ‘connect’ in base ‘null instance’ on a null instance. The only way to avoid that is to only use the connect function without specifying the emitting node, but even then it doesn’t work.

Here is my structure so far:
Level 01.tscn:
LevelNode
GameWorld

Main.tscn:
MainNode

The script for the MainNode looks the following at the moment:

extends Node2D

func _ready():
	get_tree().change_scene("res://levels/Level 01.tscn")
	get_node("GameWorld").connect("game_won_signal", self, "_on_level01_won")


func _on_level01_won():
	get_tree().change_scene("res://levels/Level 02.tscn")

But I’ve also tried quite a few variations of the connect code.
Does anybody have an idea on how to fix this? What am I doing wrong?

:bust_in_silhouette: Reply From: BlotoPK

I think that when you do get_node(“GameWorld”) you’re trying to get a node CHILD of the node in which the script is attached: MainNode. So that is the error, because that node doesn’t exist like a child of MainNode.

How do I fix this then? Neither get_node("/root/LevelNode/GameWorld)… nor find_node("GameWorld")… work. Is there even a way to resolve this?

Izaro | 2023-02-06 23:53

You can always do get_tree().root.get_node(“some_node/some_child”), but don’t know if that is what you want.
What is your currently root scene?
In your code, you’re changing the current root scene (like the parent of all scenes), so when you do get_tree().change_scene(“res://levels/Level 02.tscn”), there will be no Main.tscn…

There is a simple way to manage a change_scene:

  • MainScene → with a script to manage levels and other stuff
    –Child Level Packed Scene (your levels)
    …Maybe a viewport with the GUI

when your level01 is won, you can call a function in the MainScene (with get_parent()) and the parent (MainScene) is the one who instanciates the level2 or whatever, with add_child(). You have to queue_free() the level1, also.

BlotoPK | 2023-02-07 01:55

Hey. I’m very sorry for the extremely late answer. I was quite busy recently and forgot that I had an open question here to be absolutely honest. But thank you for that answer!!

You’re absolutely right, I somehow misunderstood what the change_scene function really does. I tired to change the code now and the instancing works, and the error is gone, but the signal doesn’t work.

The code in the MainNode script now looks like this:

extends Node2D

var current_level = 1

func _ready():
	var lvl01_load = load("res://levels/Level 01.tscn")
	var lvl01 = lvl01_load.instance()
	add_child(lvl01)
	lvl01.connect("game_won_signal", self, "on_game_won")
func on_game_won():
	print("Test")
	queue_free()
	current_level += 1
	match current_level:
		2:
			var lvl02_load = load("res://levels/Level 02.tscn")
			var lvl02 = lvl02_load.instance()
			add_child(lvl02)

The part where the signal is emitted inside the level-script looks like this:

if non_green_amount == 0 and not level_won == true:
	level_won = true
	emit_signal("game_won_signal")
	print("Yay")

The “Yay” is printed, but the on_game_won function isn’t called. What is the problem here?

Izaro | 2023-02-21 18:22