Safe to reference sceneTree nodes in _init() ?

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

As the title says …

I have a Menu scene that is preloaded and instantiated, but not yet added to the main sceneTree.
In the Menu, I need to get references to buttons, connect their signals to methods, and enable/disable some of the btns.
I usually do stuff like that in _ready(), but since the Menu is not part of the sceneTree, I can’t use that.

So : _init().
But is this safe to use ? I know that in other programming languages you shouldn’t touch nodes until the nodeTree is ready …

I’m not perfectly safe here but are you sure that _ready() isn’t called?

Godot notifications — Godot Engine (latest) documentation in English

“When instantiating a script or a standalone scene, nodes are not added
to the SceneTree upon creation, so no _enter_tree callbacks trigger.
Instead, only the _init and later _ready calls occur.”

As I understand _init() will be callled first for the parent, then for the childs (on _ready it’s the other way round AFAIK). So you may not get references to the button in the parents _init()?

But as I said on the begin, I’m not safe on this. If _ready() works, it should be safe to use though.

wombatstampede | 2019-02-19 15:26

Yeah, I’m sure _ready() isn’t called, but _init() is.
I have Menu instantiated in a global script (autoload), like this :

func _ready():              # global.gd
# preload menu and keep around
var m = preload("res://scenes/Menu.tscn")
menu = m.instance() # this does not trigger Menu._ready() !!!

In Menu.tscn, I have :

func _init():
print("init")    # is called from global.gd

func _ready():
print("ready")   # is NOT called

siska | 2019-02-19 16:01

:bust_in_silhouette: Reply From: eska

_init() is the constructor and in that sense is supposed to be used for internal state initialization. It’s possible to set up the scene from here as well, but there are cleaner alternatives.

The direct and indirect children of the scene’s root node receive the PARENTED notification one by one as they are added to the isolated node tree. You can hook into this notification by checking for NOTIFICATION_PARENTED in the _notification() callback:

func _notification(what):
	match what:
		NOTIFICATION_PARENTED:
			print("node added as child to its direct parent")

Nodes are added from top to bottom, depth-first.

Finally, by the same mechanism, the root node of the scene receives NOTIFICATION_INSTANCED once all children have been added to their parents. Since the root node does not have a parent during scene instantiation, it will not receive the NOTIFICATION_PARENTED notification.

Great explanation ! Thank you !

NOTIFICATION_INSTANCED works perfectly for what I want to do.

siska | 2019-02-20 09:47