Проблема
Вам необходимо понять, в каком порядке Godot обрабатывает узлы в дереве сцены.
Решение
Термин «порядок дерева нод» часто упоминается в документации Godot и учебных пособиях. Тем не менее, начинающему не всегда ясно, что подразумевается под этим. В общем, узлы обрабатываются в порядке сверху вниз, начиная от корня и спускаясь по каждой ветви по очереди.
Порядок дерева сцены может вызывать много путаницы у новичков в Godot. В этом примере мы поясним, в каком порядке это происходит.
Вот наш примерный набор узлов:


К каждому узлу прикреплен следующий скрипт:
extends Node
func _init():
# Note: a Node doesn't have a "name" yet here.
print("TestRoot init")
func _enter_tree():
print(name + " enter tree")
func _ready():
print(name + " ready")
# This ensures we only print *once* in process().
var test = true
func _process(delta):
if test:
print(name + " process")
test = false
Перед тем как говорить о результатах, давайте рассмотрим, что представляет собой каждая из этих функций обратного вызова:
- _init() вызывается при первом создании объекта. Теперь он существует в оперативной памяти компьютера.
- _enter_tree() вызывается, когда нода впервые входит в дерево. Это может произойти при инстанциировании или при использовании add_child(), например.
- _ready() вызывается, когда узел и его дети были добавлены в дерево и готовы к использованию.
- _process() вызывается на каждом кадре (обычно 60 раз в секунду) для каждого узла в дереве.
Если бы мы запустили это на одном узле в изоляции, порядок был бы таким, как вы, возможно, ожидаете:
TestRoot init
TestRoot enter tree
TestRoot ready
TestRoot process
Проверь свои знания в нашем бесплатном ТЕСТЕ по Godot! Узнай, насколько хорошо ты его знаешь!
Как только мы добавим дочерние узлы в дерево, ситуация становится немного сложнее и, вероятно, требует некоторых пояснений:
TestRoot init
TestChild1 init
TestChild3 init
TestChild2 init
TestRoot enter tree
TestChild1 enter tree
TestChild3 enter tree
TestChild2 enter tree
TestChild3 ready
TestChild1 ready
TestChild2 ready
TestRoot ready
TestRoot process
TestChild1 process
TestChild3 process
TestChild2 process
Как видите, все узлы вывели свои сообщения в порядке дерева, сверху вниз, следуя сначала ветвям — за исключением кода _ready().
Вот цитата из справочника Node:
Вызывается, когда узел «готов», то есть, когда и узел, и его дети входят в дерево сцены. Если у узла есть дети, их функции обратного вызова _ready вызываются первыми, и уведомление о готовности будет передано родительскому узлу после этого.
Отсюда вытекает важное правило, которое стоит помнить при настройке структуры узлов:
Совет: Родительские узлы должны управлять своими детьми, а не наоборот.
Это означает, что любой код в родительском узле должен иметь полный доступ ко всем данным в его дочерних нодах. По этой причине _ready() должен обрабатываться в обратном порядке дерева.
Помните об этом, когда пытаетесь получить доступ к другим узлам в _ready(). Если вам нужно подняться по дереву к родителю, вероятно, следует выполнять этот код в родителе, а не в дочернем узле.