How can I duplicate a node including all it's children?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By EAngeles02
:warning: Old Version Published before Godot 3 was released.

There is a method to duplicate a node but it does not comes with its children, any thoughts?

I guess your’e asking to do it using the Script, right?

genete | 2016-05-13 06:24

I don’t know which method you use to clone, but the duplicate feature in the editor duplicate the node tree for me, shortcut is Meta+D (on Mac). I’m using Godot 2.0.2.

azurvii | 2016-05-13 07:13

:bust_in_silhouette: Reply From: raould

for me, of late, I seem to have come to the conclusion that you have to do it by instancing another Scene. http://docs.godotengine.org/en/latest/tutorials/step_by_step/instancing.html

:bust_in_silhouette: Reply From: amazoniani

Sorry for repeating, but I’ve worked on this for days and it’s a total pain in the ***, so I must confirm what raould said.

Just to be clear: Duplicate your scene (tscn file) and rename it with something else, then instance() it via script or on the editor.

You get a perfect unique duplicate of the scene with all its subnodes and everything, without using the duplicate() method which made me agonize.

(The duplicate() method works OK but the subnodes won’t be unique.)

Cheers to Raould , I’ve come to the same conclusion as you!

this doesn’t duplicate scripts in scene!
all new script edits override the old copy that we needed to keep

lovegd | 2018-05-23 01:30

:bust_in_silhouette: Reply From: takaturre

Actually all the children nodes are duplicated recursively automatically. * However, they will not be saved along the packed scene unless their owner is set accordingly. So, the solution is to run a recursive loop on the kids and “own” each one by their grandpa - ie. the original node to be duplicated: kid_node.owner = grandpa_node.

Here is a general static method for this purpose:

# Own recursively - supporting ignoring nested instanced scenes (.filename).
static func own(node, new_owner):
	if not node == new_owner and (not node.owner or node.filename):
		node.owner = new_owner
	if node.get_child_count():
		for kid in node.get_children():
			own(kid, new_owner)

And using above, the solution to the original problem:

 own(grandpa_node, grandpa_node) 

_ * I don’t know if there is a way to not duplicate all the children with duplicate. Thought thatduplicate(8) flag (see Node.DuplicateFlags) would be needed to duplicate all the kids, but seems duplicate(0) also does this.

Edit:
If you are working within the editor (tool script) and want to see your nodes immediately in the scene tree, own them by the editor scene instead: get_tree().get_edited_scene_root().

thanks a lot for this tip, here is the code i’ve used with to generate packedscenes, it works like a charm!!

# your method
static func own(node, new_owner):
    if not node == new_owner and (not node.owner or node.filename):
        node.owner = new_owner
    if node.get_child_count():
        for kid in node.get_children():
            own(kid, new_owner)

further in the code:

for i in range( 0, 10 ):
	var board = load("res://models/board.tscn").instance()
	board.depth = i
	add_child( board )
	# this is a tool func of the board to regenerate all objects
	board.do_generate()
	own( board, board )
	var path = str( i )
	while len( path ) < 3:
		path = "0" + path
	path = "res://models/boards/board_" + path + ".tscn"
	var ps = PackedScene.new()
	var result = ps.pack(board)
	if result == OK:
		ResourceSaver.save(path, ps)
		print( "board saved at " + path )

frankiezafe | 2020-01-09 16:35

The recursive re-parenting is making problems when the scene is containing imported scenes. My board has this structure:

board
– buttons
---- button.tscn
---- button.tscn
---- button.tscn
---- button.tscn
---- …
– slots
---- slot.tscn
---- slot.tscn
---- slot.tscn
---- …

when running own() on board, all elements contained in button.tscn and slot.tscn gets duplicated

Due to my hierarchy, it is easy to limit to re-parenting at a specified depth:

func own( node, new_owner, lvl, max_lvl ):
	if lvl >= max_lvl:
		return
	if not node == new_owner and (not node.owner or node.filename):
		node.set_owner( new_owner )
	lvl += 1
	for c in node.get_children():
		c.set_owner( new_owner )
		own( c, new_owner, lvl, max_lvl )

And calling it like this:

own( board, board, 0, 2 )

This prevents the imported scenes to be duplicated…

frankiezafe | 2020-01-09 17:20

For Godot 4, node.filename has been renamed to node.scene_file_path (link)

GHDE | 2023-06-22 17:33