IgdrasilSceneSystem — Управление сценами
Обзор
IgdrasilSceneSystem — модуль управления игровыми сценами. Предоставляет:
- Scene — контейнер для сущностей, систем и камер.
- SceneManager — загрузка, выгрузка, переключение между сценами.
- Collection — базовый класс для группировки сущностей и систем с автоматическим вызовом lifecycle-методов.
Быстрый старт: создание и загрузка сцены
using IgdrasilEngine.Engine.ECS;
using IgdrasilEngine.Engine.SceneManagement;
// 1) Инициализация менеджера сцен (один раз при старте игры)
SceneManager.Initialize();
// 2) Создание сцены
var mainMenu = new Scene();
mainMenu.Name = "MainMenu";
// 3) Добавление сущности
var logo = new Entity { Name = "Logo", IsActive = true };
mainMenu.Entities.Add(logo);
// 4) Регистрация сцены в менеджере
SceneManager.Add("MainMenu", mainMenu);
// 5) Загрузка сцены
SceneManager.Load("MainMenu");
// Теперь сцена активна: SceneManager.Current == mainMenu
Создание сцены с системами
var gameScene = new Scene();
// Добавить систему рендеринга
var renderSystem = new SpriteRenderSystem();
renderSystem.IsActive = true;
gameScene.Systems.Add(renderSystem);
// Добавить систему физики
var physicsSystem = new PhysicsSystem();
physicsSystem.IsActive = true;
gameScene.Systems.Add(physicsSystem);
// Добавить сущности
var player = new Entity { Name = "Player", IsActive = true };
player.AddComponent(new TransformComponent { X = 100, Y = 100 });
player.AddComponent(new SpriteComponent { Texture = "player.png" });
gameScene.Entities.Add(player);
// Зарегистрировать и загрузить
SceneManager.Add("Level1", gameScene);
SceneManager.Load("Level1");
Что происходит при загрузке:
- Выгружается текущая сцена (если есть): вызов
End()для всех систем. - Новая сцена становится активной:
SceneManager.Current = gameScene. - Вызывается
Start(): системы и сущности инициализируются. - Каждый кадр автоматически вызывается
Update(deltaTime).
Загрузка сцены из файла
// Зарегистрировать путь к сцене
SceneManager.ScenePaths["Level1"] = "Assets/Scenes/Level1.scene";
// Синхронная загрузка (блокирующая)
SceneManager.Load("Level1");
// Асинхронная загрузка
var status = SceneManager.LoadAsync("Level1", autoSwap: true);
// autoSwap: true — сцена активируется автоматически после загрузки
// Проверить статус загрузки
while (!status.IsLoaded)
{
await Task.Delay(16);
}
Создание копии сцены
Полезно для уровней, которые нужно перезапускать без сохранения изменений:
// Первая загрузка — оригинал
SceneManager.Load("Level1");
// ... игрок проходит уровень, меняет сущности ...
// Перезапуск уровня — загружается свежая копия
SceneManager.LoadCopy("Level1");
// Все изменения из предыдущего прохождения сброшены
Как работает: LoadCopy сериализует оригинальную сцену через AssetBundle и десериализует в новый экземпляр.
События сцен
// Подписка на загрузку сцены
SceneManager.OnSceneLoaded += (scene) =>
{
Console.WriteLine($"Loaded: {scene.Name}");
// Инициализация UI, загрузка дополнительных ресурсов
};
// Подписка на выгрузку
SceneManager.OnSceneUnloaded += (scene) =>
{
Console.WriteLine($"Unloaded: {scene.Name}");
// Очистка ресурсов, сохранение прогресса
};
// Загрузка сцены вызовет события
SceneManager.Load("Level2");
Работа с сущностями в активной сцене
var currentScene = SceneManager.Current;
if (currentScene == null)
{
Console.WriteLine("No scene loaded");
return;
}
// Добавить сущность
var enemy = new Entity { Name = "Goblin", IsActive = true };
currentScene.Entities.Add(enemy);
// Найти сущность
var player = currentScene.Entities.FirstOrDefault(e => e.Name == "Player");
// Удалить сущность
currentScene.Entities.Remove(enemy);
// Получить все активные сущности
var activeEntities = currentScene.Entities.Where(e => e.IsActive).ToList();
Работа с системами
// Добавить систему в активную сцену
var aiSystem = new AISystem();
aiSystem.IsActive = true;
SceneManager.Current?.Systems.Add(aiSystem);
// Временно отключить систему
aiSystem.IsActive = false;
// Удалить систему
SceneManager.Current?.Systems.Remove(aiSystem);
// Получить все активные системы
var activeSystems = SceneManager.Current?.Systems
.Where(s => s.IsActive)
.ToList();
Скриптовая интеграция (Lua/MoonScript)
См. Скриптовая интеграция сцен для подробностей.
local scene = require("scene")
local ecs = require("ecs")
-- Загрузка сцены
scene.loadScene("Level1")
-- Создание и добавление сущности
local player = ecs.createEntity("Player")
scene.addEntityToScene(player)
-- События
local events = require("scene.events")
events.onSceneLoaded(function(scn)
print("Scene loaded!")
end)
Когда что использовать
Scene vs Collection
Scene — используйте для игровых уровней, меню, любых экранов с рендерингом.
- Имеет камеры, буферы трансформаций, очереди рендеринга.
- Автоматически интегрируется с рендер-системой движка.
Collection — используйте для логических группировок без рендера.
- Подходит для менеджеров, пулов объектов, вложенных групп.
- Легковеснее Scene.
// Хорошо: сцена для уровня
var level = new Scene();
level.Entities.Add(player);
level.Systems.Add(renderSystem);
// Хорошо: коллекция для группы NPC
var npcPool = new Collection();
npcPool.Entities.Add(npc1);
npcPool.Entities.Add(npc2);
level.Collections["NPCs"] = npcPool;
Load vs LoadCopy
Load — когда изменения сцены должны сохраняться между загрузками.
SceneManager.Load("MainMenu"); // Всегда одна и та же сцена
LoadCopy — когда нужна чистая копия (перезапуск уровня, рандомные вариации).
SceneManager.LoadCopy("Level1"); // Каждый раз новая копия
Sync vs Async загрузка
Синхронная — для небольших сцен, загрузочных экранов, меню.
SceneManager.Load("MainMenu"); // Блокирует поток до загрузки
Асинхронная — для больших уровней с прогресс-баром.
var status = SceneManager.LoadAsync("HugeLevel", autoSwap: false);
while (!status.IsLoaded)
{
progressBar.Value = status.Progress;
await Task.Delay(16);
}
status.SwapScene(); // Активировать вручную
Типичные сценарии
Переход между уровнями
// Завершить текущий уровень
SceneManager.Unload();
// Загрузить следующий
SceneManager.Load("Level2");
Пауза и UI-оверлеи
// Основная сцена продолжает работать
var gameScene = SceneManager.Current;
// Добавить UI как вложенную коллекцию
var pauseMenu = new Collection();
pauseMenu.Entities.Add(pauseButton);
gameScene.Collections["PauseUI"] = pauseMenu;
// Или создать отдельную UI-сцену поверх
// (требует поддержки нескольких активных сцен — зависит от архитектуры)
---
**Проект:** Igdrasil Engine
**Автор:** Alexander Izmailov
**Собственность:** Igdrasil Project
**Версия:** 1.0
**Лицензия:** [Proprietary License](license)
© 2026 Alexander Izmailov. Все права защищены.
Этот программный продукт является собственностью студии Igdrasil Project.