IgdrasilSceneSystem — Управление сценами

Обзор

IgdrasilSceneSystem — модуль управления игровыми сценами. Предоставляет:


Быстрый старт: создание и загрузка сцены

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");

Что происходит при загрузке:


Загрузка сцены из файла

// Зарегистрировать путь к сцене
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 — используйте для логических группировок без рендера.

// Хорошо: сцена для уровня
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.