How to reparent nodes with GDScript

2min read
Game Dev Godot Engine

December 16, 2018

Formula thumbnail

While working on a card game with Godot (the code will soon be open sourced), I had to reparent a node from one parent to another. Here it is two simple ways to do it.

The problem

Essentially I wanted to move the Card node from the PlayerCards container to the Field container (a grid where the cards are played).

Every node named `Container` may or may not contain a card.

Let’s take an example for the sake of clarity: suppose that we want to move the card from PlayerCards/Container0 node to Field/Container4 node.

First try

The code that I came up at first was:

# Field.gd (script attached to Field node)

func add_card_at_position(card_container, field_container_index):	
    # get the Card node
	var card = card_container.get_child(0)
    # move the card into the Container4 (hyp: container_index = 4)
	get_node("Container" + str(field_container_index)).add_child(card)
	# free memory
	card_container.queue_free()

In our exampe card_container, the first parameter in the function, is a reference to the Container4 node. So we get its child, that essentially is a Card node and then try to reparent it to move it into the field.

But I had this error:

Can't add child 'Card' to 'Container4', already has a parent 'Container0'.

The problem is that I’m trying to move the Card node that already has a parent.

In Godot one node can have only one parent at a time.
Since Godot doesn’t have a reparent() method (as far as I am aware at least, but I’m going to ask to the development team on Discord and update this post eventually), we have to make this thing by ourselves.

The solution

Pretty simple, you need to remove the node from the parent before assign it to a new one:

func add_card_at_position(card_container, field_container_index):	
	# duplicate is needed to workaround the error
	var card = card_container.get_child(0)
    # remove card from its parent (ugh...)  <----- solution
    card_container.remove_child(card) #     <----- solution
	# free memory
	card_container.queue_free()
    # add child to the Container4 (hyp: container_index = 4)
	get_node("Container" + str(field_container_index)).add_child(card)

An alternative solution: duplicate()

Another workaround that can be useful in some cases is to simply create a duplicate of the Card node and then move the cloned object to the Field.

func add_card_at_position(card_container, field_container_index):	
	# duplicate is needed to workaround the error
	var card = card_container.get_child(0).duplicate()
	# free memory
	card_container.queue_free()
    # add child to the Container4 (hyp: container_index = 4)
	get_node("Container" + str(field_container_index)).add_child(card)

If you need to duplicate hundreds of objects in a short time frame, then this may not be the best solution for you.

comments powered by Disqus