import Game from "./core/Game"; import SceneManager from "./scene/SceneManager"; import { BaseScene } from "./scene/BaseScene"; import type { IBaseScene } from "./scene/types"; import { SceneType } from "./enums/SceneType"; import { assetManager } from "./core/AssetManager"; import { logger } from "./core/Logger"; import eventBus from "./core/EventBus"; import { Container } from "pixi.js"; const game = Game.getInstance(); const sceneManager = SceneManager.getInstance(); type Constructor = new (...args: unknown[]) => T; export async function initApp(): Promise { await assetManager.init(); await game.init(); const sceneModules = import.meta.glob("./stages/**/page_*.ts", { eager: true }); for (const path in sceneModules) { try { const mod = sceneModules[path]; const match = path.match(/page_(.*?)\.ts$/); if (!match) continue; const fileSceneName = match[1]; const raw = (mod as { default: unknown }).default; if (typeof raw !== "function") { logger.warn(`initApp: invalid scene file ${path}, expected default class export, skipping`); continue; } const SceneCtor = raw as Constructor>; const scene = new SceneCtor(); if (!scene || typeof scene !== "object" || !("stage" in scene)) { logger.warn(`initApp: invalid scene file ${path}, skipping`); continue; } const legacy = scene as IBaseScene & Record & { name?: string; type?: SceneType }; const mutable = legacy as { name?: string; type?: SceneType; stage: Container | null }; if (!mutable.name) { mutable.name = fileSceneName; } if (mutable.type === undefined) { mutable.type = SceneType.Normal; } if (!mutable.stage) { mutable.stage = new Container(); } sceneManager.registerScene(legacy as IBaseScene); } catch (error) { logger.error(`initApp: failed to load scene file ${path}`, error); } } game.ticker.add((ticker) => { const dt = ticker.deltaTime; const current = sceneManager.currentScene; for (const scene of sceneManager.getAllScenes()) { if (scene.type === SceneType.Resident && scene.stage.visible) { scene.update?.(dt, scene.name, ticker); } } if (current) { current.update?.(dt, current.name, ticker); } game.render(); for (const scene of sceneManager.getAllScenes()) { if (scene.type === SceneType.Resident && scene.stage.visible && scene.lateUpdate) { scene.lateUpdate(dt, scene.name, ticker); } } if (current?.lateUpdate) { current.lateUpdate(dt, current.name, ticker); } }); const residentScenes: BaseScene[] = []; for (const scene of sceneManager.getAllScenes()) { if (scene.type === SceneType.Resident) { residentScenes.push(scene as BaseScene); } } for (const scene of residentScenes) { try { if (!scene._assetsLoaded) { await scene.loadBundle?.(); scene._assetsLoaded = true; } if (!scene._layoutDone) { await scene.layout?.(); scene._layoutDone = true; } await scene.onLoad?.(); } catch (error) { logger.error(`initApp: failed to initialize resident scene ${scene.name}`, error); } } const entryScene = "init"; if (sceneManager.hasScene(entryScene)) { await sceneManager.initScene(entryScene); } else { logger.error(`initApp: entry scene "${entryScene}" not found`); } sceneManager.onStageChange((current) => { logger.debug("Scene changed to", current.name); }); logger.info("App initialized"); } export { game, sceneManager, eventBus, assetManager, logger };