【Godot4】queue_free()したNodeが削除されずget_children()で取得される原因と対処法
2026-06-10
Godotでノードを削除するときにqueue_free()を使ったのに、
直後のget_children()では削除したはずのノードがまだ取得されることがあります。
この記事では、queue_free()が即時削除ではないことと、
手札やカード一覧のように子ノードを並び替える処理での対処法を紹介します。
環境
- Godot4.5
- GDScript
問題例
次のように、カードゲームの手札を横並びに表示する場面を考えます。
ここでは、handsの子ノードとして各カードが追加されており、
それぞれのpositionを以下のコードで直接指定しています。
var i = 0
for card in hands.get_children():
card.position = Vector2(100, 0) * i
i += 1
ここで手札を1枚捨てたあと、残ったカードの表示位置を詰めようとすると、次のようなコードになります。
trash_card.queue_free()
var i = 0
for card in hands.get_children():
card.position = Vector2(100, 0) * i
i += 1
まず手札が3枚用意します。

この時、真ん中のカードを捨ててみます。

実行すると、削除したカードがまだget_children()に含まれているため、残ったカードの位置が期待通りに詰まりません。
こうなる原因はqueue_free()が即座に削除されるのでなく、現在のフレームの最後に削除されるため、並び替えるときのhands.get_children()にqueue_free()したカードが残っているからです。
修正案
対処法1:次のフレームまで待つ
削除が反映されたあとに並び替える方法です。
queue_free()した後に1フレームだけ待つことで削除されるまで待機します。
trash_card.queue_free()
await get_tree().process_frame
var i = 0
for card in hands.get_children():
card.position = Vector2(100, 0) * i
i += 1
対処法2:先に親から外す
remove_child()で先にhandsの子ノード一覧から外すことで、get_children()の対象からすぐに除外できます。
hands.remove_child(trash_card)
trash_card.queue_free()
var i = 0
for card in hands.get_children():
card.position = Vector2(100, 0) * i
i += 1
対処法3:削除対象をスキップする
一時的に削除対象だけを除外したい場合に使えます。
trash_card.queue_free()
var i = 0
for card in hands.get_children():
if card == trash_card:
continue
card.position = Vector2(100, 0) * i
i += 1
まとめ
queue_free()は即時削除ではなく、削除予約です。
そのため、直後にget_children()すると削除予定のノードが含まれることがあります。
手札や一覧UIのように、子ノードをすぐ並び替えたい場合は、
- 次のフレームまで待つ
remove_child()で先に親から外す- 削除対象を処理から除外する
といった方法で対応できます。