Onready variables lose their nodes

Godot Version

godot_v4.1.3

Question

I set a few onready variables with nodes. Everything worked, but when i use a function activated by a signal from a difrent scene, all of this variables are null. How can I fix it?

extends Node2D
var Player1= "guild_dwarves_first"
var Player2 = "cave_goblins_first"
var activePlayer = 1
const resPath = "res://Resources/Cards/"
@onready var DB = $DeckDB
@onready var CardScene = preload("res://Scenes/card.tscn")
@onready var DrawPile = [$"Board/Player 1/Draw", $"Board/Player 2/Draw"]
@onready var Magic = [$"Board/Player 1/Magic", $"Board/Player 2/Magic"]
@onready var Discard = [$"Board/Player 1/Discard", $"Board/Player 2/Discard"]
@onready var Hand = [$"Board/Player 1/Hand", $"Board/Player 2/Hand"]
@onready var Battleground = $"Board/BattleGround"
var GamePhase = "build_magic"
func _ready():
	prepare() #This appears first, and all variables have their nodes

func field_activated(field):
	#Magic = [$"Board/Player 1/Magic", $"Board/Player 2/Magic"] #I tried this, but doesn't work neither
	var card
	if GamePhase == "summon":
		pass
	if GamePhase == "event":
		pass
	if GamePhase == "move":
		pass
	if GamePhase == "attack":
		pass
	if GamePhase == "build_magic":
		if field.get_child_count() != 0:
			card = field.get_child(0)
			field.remove_child(card)
			card.reverse()
			Magic[activePlayer].add_child(card) #This appears later, and all variables are null


extends ColorRect
signal active_filed

func _ready():
	var main = preload("res://Scenes/main.tscn").instantiate()
	connect("active_filed",Callable(main, "field_activated"))

func _on_gui_input(event):
	if event.is_action_pressed("click"):
		active_filed.emit(self)

Could you try connecting the signal like this:

active_filed.connect(main.field_activated)

Same result

As you see, connection works, but onready variables seem lose their data

Ok, I solved it Xd
Its all because I set main in ColorRect as new node whitch doesn’t have its place in tree.
All i had to do was changing

	var main = preload("res://Scenes/main.tscn").instantiate()

with

	var main = get_tree().get_root().get_node("Main")
2 Likes

Glad you solved it, and do forgive me for coming with unasked-for advice… but it can help you not run into these in the future.

As a general good programming practice, child nodes should have zero knowledge of parent nodes. Every time you’re tempted to write “get_tree().get_root().get_node…”, it’s an indication to consider another way, such as an Event bus pattern.

In this case, you may have an Events singleton (Autoloaded via Project → Settings) that defines the signal “active_filed(field)”. The Main scene would then connect to it via “Events.active_filed.connect()” in its _ready(). It can react based on what value “field” parameter contains.

Another way is for a parent to connect to child node’s signals. That’s also okay. So app-wide signal, or top-down, but never bottom-up.

Feel free to ignore, ofc, just wanted to share a lesson I learned in my career. <3

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.