Создать экземпляр и сохранить дерево Entity
Parent, Owner и PackedEntity; почему дочерний объект работает в игре, но исчезает после сохранения.
Parent и Owner решают разные задачи
Parent задаёт иерархию, наследование преобразований и жизненный цикл дочерних объектов. AddChild добавляет объект в эту иерархию. Owner указывает, какому сохраняемому дереву принадлежит Entity. Он должен быть предком; корню не назначают самого себя владельцем.
В обычном дереве, которое вы строите кодом для сохранения, после AddChild назначайте child.Owner = root. Это не требуется каждому временному снаряду только ради работы в игре. Вложенный экземпляр префаба уже имеет собственные области Owner: не переписывайте их всем потомкам одним циклом.
Проверить сохранение
Добавьте OwnerPackingDemo.cs в C#-проект 1.0.0, прикрепите к Entity отдельного тестового уровня, соберите и нажмите F6. В Output появится Owner packing: Ok; в user:// создастся OwnedExample.rprefab. Откройте папку пользовательских данных проекта и проверьте файл: Saved есть, Transient нет. Пример перезаписывает только указанный учебный файл.
OwnerPackingDemo.cs
using Reckfell;
public partial class OwnerPackingDemo : Entity
{
public static Error SaveExample(string path)
{
if (!path.EndsWith(".rprefab") && !path.EndsWith(".rscene")) return Error.InvalidParameter;
var root = new Entity2D { Name = "OwnedExample" };
try
{
var saved = new Entity2D { Name = "Saved", Position = new Vector2(12, 34) };
root.AddChild(saved);
saved.Owner = root;
var transient = new Entity { Name = "Transient" };
root.AddChild(transient);
using var packed = new PackedEntity();
Error error = packed.Pack(root);
return error == Error.Ok ? ResourceSaver.Save(packed, path) : error;
}
finally
{
root.Free();
}
}
public override void _Ready()
{
Error error = SaveExample("user://OwnedExample.rprefab");
ReckfellApi.Print("Owner packing: " + error);
}
}Pack создаёт снимок сериализуемого дерева, а не автоматически сохраняет его на диск. Только после успешного Pack вызывается ResourceSaver.Save. Для загрузки используйте ResourceLoader.Load<PackedEntity>, проверьте результат и CanInstantiate, затем Instantiate. Новый корень ещё не прикреплён: настройте нужные свойства и передайте его в AddChild.
В тесте исходный root освобождается после Pack, а новый экземпляр восстанавливает Saved.Position и Owner. Это отдельные Entity. Другие Resource-ссылки внутри префаба могут оставаться общими: создание Entity не означает глубокую копию всех материалов и текстур.
Почему ребёнок пропал
| Причина | Действие |
|---|---|
| Есть Parent, но нет нужного Owner | Назначить Owner после добавления к предку |
| Без Owner оставлен промежуточный контейнер | Проверить всю сохраняемую ветку: Pack может пропустить её вместе с потомками |
| Сохранён другой root | Передать корень того дерева, которое нужно восстановить |
| Сохранён PackedEntity до изменения объектов | Повторить Pack после изменения; он не следит за живым деревом |
| Вложенный префаб получил чужого Owner | Сохранить его собственную структуру и менять только нужные переопределения |
PackedEntityState.GetEntityCount считает записи снимка, а не всех потомков, которые появятся после раскрытия вложенных префабов. В примере уровня сохранены три записи — корень и две ссылки на префаб; реальных потомков после Instantiate больше.
Создание и удаление во время игры
_EnterTree вызывается при входе, _Ready — после готовности детей. Если создаваемый объект использует настройки или испускает сигнал в _Ready, задайте их и подключите обработчики до AddChild. Для переиспользуемого объекта не рассчитывайте на повторный _Ready при каждом входе.
QueueFree ставит удаление в очередь; ссылка ещё может существовать до обработки очереди. После освобождения C#-переменная не гарантирует живой native-объект: проверяйте ReckfellObject.IsInstanceValid и не обращайтесь к удалённой Entity. RemoveChild только отсоединяет; он не освобождает объект. За отсоединённым объектом должен остаться владелец жизненного цикла.