SceneTree packedScene duplicate child nodes (inside packed scene and outside of packed scene)

Godot Version

4.2.1

Question

I have a packedScene used for my game characters which I add to my main scene, the packed scene contains a set of sprite2D nodes (The scene is a paper doll setup, layered 2D sprites). The packed scene deletes and recreates the sprite2D nodes when instantiated - I apply ordering, textures and materials during this process. As a standalone scene it works fine. However when I add this as an instantiated scene to my world (as a the player or as an NPC for example) the SceneTree populates with the scene and a set of newly generated child Sprite2D nodes, while within the packed scene there is another set of child Sprite2D nodes. This causes issues because the animation of the character has a duplicated static sprite behind it at all times (from the duplicate set of sprite2D nodes) - I suspect this is to do with having the character scene as a tool script - This allows me to generate different characters in the editor.

I do get loading errors when working with the main scene or when running the game (Side question: they pop up and disappear too quick for me to read - does anyone know where these are stored or how I can stop the load error screen from disappearing so quickly?)

How do I prevent the packed scene from creating nodes outside of the packed scene? - or how do I delete the nodes inside or outside so that I only have one set of nodes - I also don’t know which set are remaining static rather than being animated - I would hope the nodes inside the packed scene are the ones being animated, since the animation player node is also inside the packed scene

Side question: How does Godot differentiate between these nodes in the scene tree? When viewing the tree while running they have the same name and live under the same parent (outside and inside the packed scene)?

Many things happening here. It depends on how you are doing things. Some kind of demo project would help us help you.

As for the various errors and such, you should be able to see them all from the Output panel (bottom of the gui). In there, on the right, you can control what shows and so forth.

Cheers @dbat

I have managed to solve via workaround for now - I only invoke the tool parts of the script if I have deleted the sprite2D nodes from the scene, and only do this when working on the scene. Not 100% sure this is a fix, but I no longer get the brief loading errors window.

Attach the script to a node2D below, save the scene and then instantiate the scene within a separate scene. It will work at first with no errors, however after saving or reloading the project it will then throw the errors - loading errors appear in a pop up only and are short lived, these don’t appear in the output dialogue or debugging tab. The only error that is displayed in the output dialogue is:

Attempting to parent and popup a dialog that already has a parent.

Here is some sample code for helping to identify my user error :blush:


@tool

extends Node2D
@export var spriteNodes: Array

func _ready() -> void:

	spriteNodes.clear()
	
	var _children := get_children()
	if _children:
		for _child in _children:
                        # Rename to prevent the replacement node below having a clash
			_child.name = _child.name+"_XX"
			_child.queue_free()
	
	for i in 2:
		var _node: Sprite2D = Sprite2D.new()
		_node.name = "Node"+str(i)
		add_child(_node)
		_node.owner = get_tree().edited_scene_root
		# Can't store nodes in a dictionary via tool script, so needs to be a path to a node
		spriteNodes.append(_node.get_path())

To add, while in the editor both the scene and the instantiated scene will have visible child nodes of the instantiated scene, these will have the same name inside the instantiated scene and shown outside of the instantiated scene but parented to the instantiated scene

*Node2D
–[the instantiated scene]
|–the children shown outside of the instantiated scene but remaining as children

However at runtime the child nodes don’t clash because they are renamed by godot to prevent conflicts. In the example code above, at runtime you will have 4 nodes rather than the intended two.

Fiddling with this. Brain is pretty foggy. Did notice this:

image

I think the error about the dialogue popup is talking about this error dialogue, not your particular code. It’s a bug, I feel.

I’ll keep poking at this a bit.

When you instance a scene (A) into another one (B), the script that is attached to the root of A becomes the script for the instance in B. This is weird, to be sure. The fix was to move the script from the root of A so that it only applies to the contents of A.

Here’s the project:

hth

1 Like

Cheers @dbat
Thanks for putting the time in, I really appreciate it. Is this expected behaviour? I couldn’t find anything in the Godot docs that warns of this.

Thanks again for the solution, I will be refactoring to adopt this pattern now :+1:

1 Like

Expected… Maybe?I keep finding this out and then forgetting it again! What ya gonna do? :smiley:

I need to play around with it, I have a lot going on in the root node script (input, collisions, public functions for changing palettes, clothing etc). I originally started out with a control script in a node of the root but then moved it all to the root to get around a problem - I can’t remember what it was now, so will probably come across it again soon lol (although have started to notice that my updated node paths now don’t work for my animation functions - when the sprite2D is created it has a huge editor path, which goes into an Array, but when I get the path from the array I just get the short node name (the array is of type nodePath, when I append “:frame” etc to this it no longer can find the node when loading in my animation data) I’ll keep fiddling with it until it works