EntityTree: сменить и перезапустить уровень
CurrentScene, отложенная смена и SceneChanged; полный обработчик кнопки без обращения к удалённому уровню.
Когда уровень действительно сменился
GetTree() доступен Entity в активном дереве. EntityTree.Root — главный Viewport, а CurrentScene — текущий корень уровня под ним. Другие дети Root, например автозагрузки, могут существовать рядом. Присваивание CurrentScene само по себе не добавляет и не освобождает объекты.
ChangeSceneToFile возвращает Error начала операции. При успехе старый корень сразу отсоединяется, CurrentScene временно null, а освобождение старого и подключение нового завершаются отложенно. SceneChanged испускается после входа нового уровня и его _Ready. Один await ProcessFrame не заменяет контракт этого сигнала.
Кнопка перехода
Подготовьте Assets/BadgeStyle.rdata, Actors/Badge.rprefab и Levels/FormatShowcase.rscene из примера формата. Добавьте оба C#-файла ниже. В отдельном уровне создайте Button, задайте видимый текст, прикрепите LevelSwitchButton, соберите и запустите F6. Нажатие заменит уровень на FormatShowcase с двумя экземплярами.
LevelTransitions.cs
using System;
using System.Threading.Tasks;
using Reckfell;
public static class LevelTransitions
{
private static bool _pending;
public static async Task<Error> ChangeAsync(EntityTree tree, string path)
{
if (_pending) return Error.Busy;
if (!path.StartsWith("asset://", StringComparison.Ordinal) ||
!path.EndsWith(".rscene", StringComparison.OrdinalIgnoreCase)) return Error.InvalidParameter;
if (!ResourceLoader.Exists(path, "PackedEntity")) return Error.FileNotFound;
_pending = true;
try
{
Error error = tree.ChangeSceneToFile(path);
if (error != Error.Ok) return error;
await tree.ToSignal(tree, EntityTree.SignalName.SceneChanged);
return Error.Ok;
}
finally
{
_pending = false;
}
}
}LevelSwitchButton.cs
using System;
using Reckfell;
public partial class LevelSwitchButton : Button
{
[Export(PropertyHint.File, "*.rscene")]
public string NextLevelPath { get; set; } = "asset://Levels/FormatShowcase.rscene";
public override void _EnterTree() => Pressed += OnPressed;
public override void _ExitTree() => Pressed -= OnPressed;
private async void OnPressed()
{
try
{
Error error = await LevelTransitions.ChangeAsync(GetTree(), NextLevelPath);
if (error != Error.Ok) ReckfellApi.PrintErr("Level change: " + error);
}
catch (Exception error)
{
ReckfellApi.PrintErr(error.ToString());
}
}
}Вызывайте helper на главном потоке и проводите через него все переходы, для которых нужна эта защита от перекрытия. .rscene — правило helper: нативный API принимает и .rprefab с PackedEntity. Существование пути не доказывает корректность содержимого; проверка Error после ChangeSceneToFile остаётся обязательной.
После await обработчик не обращается к кнопке: она могла быть освобождена со старым уровнем. Если после перехода нужно обновить интерфейс, найдите его в новом CurrentScene либо используйте управляющую Entity, которая живёт вне заменяемого корня.
Helper не реализует загрузочный экран, background streaming или отмену. Нельзя параллельно заменять уровень через другой контроллер и вручную освобождать ожидающий подключения корень: это нарушит его ожидание SceneChanged.
Перезапуск и ручное управление
ReloadCurrentScene загружает CurrentScene.SourceAssetPath заново. Это восстановление состояния файла, а не перезапуск с текущими изменёнными полями. У уровня, созданного из new Entity и переданного в ChangeSceneToEntity, может не быть исходного файла: сохраняйте PackedEntity/путь отдельно, если нужен повторный запуск.
ChangeSceneToEntity принимает ещё не включённый в активное дерево корень. Если вместо этого добавить его через Root.AddChild и просто назначить CurrentScene, автоматического удаления прежнего корня не произойдёт.
UnloadCurrentScene освобождает текущий корень сразу. Не продолжайте после этого обращаться к его объектам. Для обычного перехода используйте согласованную смену уровня, а долгоживущие данные держите отдельно от заменяемого дерева.
Что проверять при сбое
| Результат | Следующий шаг |
|---|---|
| InvalidParameter от helper | asset:// и расширение .rscene; UID сначала разрешить в корректный путь |
| FileNotFound | Файл и включение нужного уровня в проект/экспорт |
| Busy | Не начинать второй переход, пока первый не завершён |
| Ошибка native-загрузки | Диагностика ресурса; старый уровень при отказе до смены остаётся |
| CurrentScene временно null | Дождаться SceneChanged, не читать старые ссылки |
Стенд проверяет реальный промежуток смены, готовность нового корня, удаление старого, отказ перекрытия, повторную загрузку и запуск из готовой Entity. Экспорт и потоковая загрузка этим сценарием не подтверждены.