1
\$\begingroup\$

How to get nested child node without using full path? I tried with just node name, it doesn't work.

The script is on top level so the path is quite long:

dialogText = GetNodeOrNull<RichTextLabel>("VBoxContainer/Panel/MarginContainer/DialogContainer/DialogTextWrapper/DialogText");

(Question originally posed on Discord and copied here.)

\$\endgroup\$

3 Answers 3

2
\$\begingroup\$

The simplest way is Node.find_child(), but that does a search each time it's called which can be slow.* When you're done prototyping, you'll want to change to another method.

You could do a Unique Name.

Or an @export in gdscript or C#.


* And by slow, I mean find_child() can be so slow that the docs warn about using it:

Note: As this method walks through all the descendants of the node, it is the slowest way to get a reference to another node. Whenever possible, consider using get_node with unique names instead (see unique_name_in_owner), or caching the node references into variable.

\$\endgroup\$
0
\$\begingroup\$

get_node(NodePath) fetches a node & can use the NodePath can be either a relative path (from the current node) or absolute. The relative path is typically shorter. When used as a literal you can further shorten the expression to $NodePath.

So with this Player scene:

enter image description here

And this PlayerGun scene:

enter image description here

Then in order to access the somewhat deeply nested Muzzle node from within my script for Player I would do this in 3.x:

onready var muzzle = $Sprite/PlayerGun/Sprite/Muzzle

or this in 4.x:

@onready var muzzle = $Sprite/PlayerGun/Sprite/Muzzle

Because I'm using a relative path, I don't need the full / absolute path. As as a bonus, the absolute path could possible change, but as long as I don't change the relative relationship between Player and Muzzle nothing breaks.

get_node() is more performant than find_node(). find_node() has to do a pattern matching search for its target whereas get_node() uses a hash map to children (which is also how unique scene nodes work).

\$\endgroup\$
5
  • \$\begingroup\$ I'm inferring the performance difference between get & find based on their definitions. If someone has a solid source that confirms or refutes my performance claim, please let me know or just add an edit. \$\endgroup\$
    – Pikalek
    Commented Oct 1, 2023 at 1:25
  • 1
    \$\begingroup\$ The method get_node would get nodes by name from a hash map of the children, this is also how unique scene nodes work. And, yes, find_node will do pattern matching. I could not find a direct performance comparison. \$\endgroup\$
    – Theraot
    Commented Oct 1, 2023 at 4:03
  • 2
    \$\begingroup\$ What I can tell you is that for Godot 4 find_node was removed to avoid misuse due to bad performance, then Scene Unique Nodes were added as a direct alternative, the reason being that people were using find_node to get nodes to prevent the code from breaking from changes in the scene tree. Although some argued that the performance wasn't a problem (you get reference once during initialization and reuse it) or that you should update the code when you change the scene tree. Ultimately find_node was restored (which eases porting from Godot 3 to 4) and subsequently renamed to find_child. \$\endgroup\$
    – Theraot
    Commented Oct 1, 2023 at 4:09
  • 1
    \$\begingroup\$ @Pikalek: "Because I'm using a relative path, I don't need the full / absolute path." But the script is on the root node, so the relative path is just as long as the absolute path. \$\endgroup\$
    – idbrii
    Commented Oct 3, 2023 at 17:10
  • \$\begingroup\$ @idbrii True however the question didn't specify a root node requirement & near the the beginning of my answer, I did qualify it with "relative path is typically shorter". That aside, the other advantages presented still stand. \$\endgroup\$
    – Pikalek
    Commented Oct 3, 2023 at 19:00
0
\$\begingroup\$

I use @export for this, especially in e.g. UI components in which I may re-organize things often that end up changing all paths.

I do something like:

@export_group("Internal")
@export var foo_button: Button
@export var bar_button: Button
...

Then you can assign your button deep within tree by either dragging or clicking on the inspector and assigning.

The main advantage of this method is that you don't have to do anything if you re-organize the tree. The references are kept even if you move nodes around, add nodes to the hierarchy, etc.

I add them to the "Internal" export group so they don't pollute the "external interface" of the scene.

The variables are assigned by the time _ready() is called.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .