+9 votes

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

in Engine by (69 points)

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

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.

3 Answers

+3 votes

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

by (103 points)
+3 votes

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!

by (22 points)

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

+1 vote

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().

by (32 points)
edited by

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 )

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...

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.