How to reference nodes inside of another scene

Godot Version

Godot Engine v4.7.1

Question

Hi! Is there a way to easily search and reference nodes inside a scene instance from outside of it?

For example, I have a CharacterSkin Scene with a Skeleton3D and multiple BoneAttachement3D inside.

My CharacterSkin scene is used in my Player scene.

What would be the most robust way to get references to my Skeleton3D and BoneAttachment3D from outside the scene? Any “access as unique name” that could work from outside the scene?

I just read this thread where the solution is using groups (get_tree().get_first_node_in_group("group_name")), but I have more questions:
Can we easily limit the search to only children of a node? for example: get_parent().get_first_node_in_group("group_name") (this doesn’t work, that is just the idea of what I’m looking for) to search only in my character’s child nodes (if I have two or more characters in my level, my nodes in group aren’t unique any more)?

Ideally, I would like having nodes that can automatically find their needed references and setup themselves in an intialize function.

Should I search all child nodes in the scene and filter them by type/name? Is it good practice? Should I worry about any performance impact?

I like get_tree().get_first_node_in_group("group_name")being one simple line, but I will make full “search children” loops if it is the way to go.

Ok, I’m realizing I totally missed the “Editable Children” feature, although I read the documentation to get started (I don’t remember if it’s in but I missed it and can’t find it searching for “editable children”).

I still have to investigate the subject, maybe my initial question is still relevant, but I feel it may be a (the?) solution. For the example I took, I understand that can simply attach my camera to the BoneAttachment3Dthat way for my example.

Since the CharacterSkin scene is a child of your player you can use $ paths, you don’t need editable children but it’s probably good to enable that for this situation. $CharacterSkin/FirstPersonView_Socket for instance will work fine.

You could search children with for child in get_children(), or parents with get_parent(), both may be costly so don’t do it every frame.

It’s a bit counter to your question, but in the interest of other points of view… and you did ask for the most robust way :stuck_out_tongue:

For accessing nodes in a different scene, I like to keep the interface at the top level object/scene, so that if (when) I change the node structure, the only code I need to update is in the top level’s script.

I usually do this with simple @onready vars. The other code just needs to find the top-level object and use it’s properties/class vars to access the guts. For your case, sth like this in the player and skin scripts:

# skin exposes skeleton and sockets (in skin.gd)
@onready var skeleton_3d : Skeleton3D = $Rig/Skeleton3D
@onready var right_hand_socket : BoneAttachment3D = $RightHand_Socket

# player exposes skin (in player.gd)
@onready var character_skin : Node3D = $CharacterSkin

# other scripts can get the player object and can use it to get to the skeleton and sockets
    player.character_skin.right_hand_socket.add_child(weapon)

Personally, I would hide that detail in a player method equip_weapon so the caller could be unaware of complications like whether another weapon is already equipped or whether the weapon is two-handed, etc. and so forth…

You can create the @onready vars easily by ctrl-dragging from the scene tree into the script window. Dragging multiple selection works, too! If you use access as unique names for anything you want to expose, you don’t even have to update the code if you change the tree. @onready var foo : Node = %foo is pretty easy to maintain.

You should never worry about performance unless you measure a bottleneck using the profiler.

Have in mind that scenes don’t really exist at runtime in the scene tree. It’s just one big tree of nodes. You can fetch any node in the tree from anywhere else in the tree - by its relative or absolute path.

Yes, I’m not sure I’ll keep the “Editable Children” solution for this (good to know this exists although), it keeps my complex scenes messy while I’m trying to get all of this out of my head and rely on my nodes and scripts to do the work for me.
If I can stick to a strict standard structure, I’ll think about using $ paths.

Good to know, thank you!

Thank you, it’s good to have multiple points of view. It can be a good solution.

Yes, it is not that I’m really worried, I’m not. It’s that I don’t have the basic knowledge about this (how to choose between these options in an ideal world). My intuition was that adding loops here instead of having everything setup in the editor would make it slower. I’m almost certain I won’t care in the end, but I’d really like to know why I can continue not caring.
My intuition is that I can “not care” not because the nature of the method, but because of its order of magnitude within my scope. To put it another way: that method maybe IS slower, but I won’t even notice it. That is where my ignorance lies.

But I understand why you saying that and I take your advice!

In a way, my whole topic is not really about me being stuck, but trying to refine my practice and avoid basic traps if there’s any.
I know these are really basic questions, but it’s where I am and I don’t really know how to look for answers on such specific questions I totally understand most people won’t care (being self-taught actually, I assume the answer is probably a tiny chapter in a whole structured training course).

Yes, it’s good to know. I watched this (Beginner’s Guide To Understand Godot Scene Tree) in the meantime, there’s a lot of the informations I needed in it.

Don’t get too obsessive about “the right way”. When learning stuff, you’re bound to make your fair share of mistakes and sub optimal approaches, no matter how much theory you read. Mistakes facilitate learning.

If an approach is slower but not noticeably - that means it’s fine. In many cases there are multiple acceptable solutions to a problem. Only worry if the performance is objectively not acceptable on your target hardware, i.e. if it affects the player experience in a negative way.

Yes, I wrote way too much about a small detail of my question I was already going to put a really small decision weight on. I thought that it was an easy 0/1 answer on an already closed case.

Already made a lot of mistakes and sub-optimal approaches, that is a good point.

My current approach is mostly try to get stuff “in my nodes” and “out of my head”, and enable me to work on the relevant level without being held back by the need to constantly manage things at small levels.

It is a viable approach. I am doing something similar in a platformer game where each level has an arbitrary number of rooms (individual scenes) connected by doors. When the level loads the first room is loaded, then it searches for doors, those doors reference other rooms (by scene UID + a door ID tag) which are loaded (and instanced), and the process repeats until no more unique rooms are discovered. Except for the first room, this all happens outside of the SceneTree. One room is current, and they are swapped in and out of the SceneTree as needed. References to the instances are kept in a map of UID strings to rooms. After the scenes are loaded, the UIDs which doors use to reference other scenes are augmented with actual references to the room instances.

In my small prototype, this process takes .006 seconds. Performance is probably not an issue unless your scenes have thousands of nodes. The individual scenes do not become _ready() until they actually enter the SceneTree for the first time, but all the loading / IO is done before gameplay starts.