You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
3.7 KiB
126 lines
3.7 KiB
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<T> = new (...args: unknown[]) => T;
|
|
|
|
export async function initApp(): Promise<void> {
|
|
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<IBaseScene & Record<string, unknown>>;
|
|
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<string, unknown> & { 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 };
|
|
|