新增scenemanager,重构core类减少多世界造成的性能压力

This commit is contained in:
YHH
2025-10-09 23:33:11 +08:00
parent 79f7c89e23
commit 7339e7ecec
10 changed files with 876 additions and 1103 deletions

View File

@@ -0,0 +1,238 @@
import { IScene } from './IScene';
import { ECSFluentAPI, createECSAPI } from './Core/FluentAPI';
import { Time } from '../Utils/Time';
import { Core } from '../Core';
import { createLogger } from '../Utils/Logger';
/**
* 单场景管理器
*
* 适用场景:
* - 单人游戏
* - 简单场景切换
* - 不需要多World隔离的项目
*
* 特点:
* - 轻量级,零额外开销
* - 简单直观的API
* - 支持延迟场景切换
* - 自动管理ECS API
*
* @example
* ```typescript
* // 初始化Core
* Core.create({ debug: true });
*
* // 创建场景管理器
* const sceneManager = new SceneManager();
*
* // 设置场景
* class GameScene extends Scene {
* initialize() {
* const player = this.createEntity('Player');
* player.addComponent(new Transform(100, 100));
* }
* }
*
* sceneManager.setScene(new GameScene());
*
* // 游戏循环
* function gameLoop(deltaTime: number) {
* Core.update(deltaTime); // 更新全局服务
* sceneManager.update(); // 更新场景
* }
*
* // 延迟切换场景(下一帧生效)
* sceneManager.loadScene(new MenuScene());
* ```
*/
export class SceneManager {
/**
* 当前活跃场景
*/
private _currentScene: IScene | null = null;
/**
* 待切换的下一个场景(延迟切换用)
*/
private _nextScene: IScene | null = null;
/**
* ECS流式API
*/
private _ecsAPI: ECSFluentAPI | null = null;
/**
* 日志器
*/
private _logger = createLogger('SceneManager');
/**
* 设置当前场景(立即切换)
*
* 会自动处理旧场景的结束和新场景的初始化。
*
* @param scene - 要设置的场景实例
* @returns 返回设置的场景实例,便于链式调用
*
* @example
* ```typescript
* const gameScene = sceneManager.setScene(new GameScene());
* console.log(gameScene.name); // 可以立即使用返回的场景
* ```
*/
public setScene<T extends IScene>(scene: T): T {
// 结束旧场景
if (this._currentScene) {
this._logger.info(`Ending scene: ${this._currentScene.name}`);
this._currentScene.end();
}
// 设置并初始化新场景
this._currentScene = scene;
this._currentScene.initialize();
this._currentScene.begin();
// 重建ECS API
if (scene.querySystem && scene.eventSystem) {
this._ecsAPI = createECSAPI(scene, scene.querySystem, scene.eventSystem);
} else {
this._ecsAPI = null;
}
// 触发场景切换回调
Time.sceneChanged();
// 通知调试管理器
const coreInstance = Core.Instance;
if (coreInstance && coreInstance._debugManager) {
coreInstance._debugManager.onSceneChanged();
}
this._logger.info(`Scene changed to: ${scene.name}`);
return scene;
}
/**
* 延迟加载场景(下一帧切换)
*
* 场景不会立即切换,而是在下一次调用 update() 时切换。
* 这对于避免在当前帧的中途切换场景很有用。
*
* @param scene - 要加载的场景实例
*
* @example
* ```typescript
* // 在某个System中触发场景切换
* class GameOverSystem extends EntitySystem {
* process(entities: readonly Entity[]) {
* if (playerHealth <= 0) {
* sceneManager.loadScene(new GameOverScene());
* // 当前帧继续执行,场景将在下一帧切换
* }
* }
* }
* ```
*/
public loadScene<T extends IScene>(scene: T): void {
this._nextScene = scene;
this._logger.info(`Scheduled scene load: ${scene.name}`);
}
/**
* 获取当前活跃的场景
*
* @returns 当前场景实例如果没有场景则返回null
*/
public get currentScene(): IScene | null {
return this._currentScene;
}
/**
* 获取ECS流式API
*
* 提供便捷的实体查询、事件发射等功能。
*
* @returns ECS API实例如果当前没有场景则返回null
*
* @example
* ```typescript
* const api = sceneManager.api;
* if (api) {
* // 查询所有敌人
* const enemies = api.find(Enemy, Transform);
*
* // 发射事件
* api.emit('game:start', { level: 1 });
* }
* ```
*/
public get api(): ECSFluentAPI | null {
return this._ecsAPI;
}
/**
* 更新场景
*
* 应该在每帧的游戏循环中调用。
* 会自动处理延迟场景切换。
*
* @example
* ```typescript
* function gameLoop(deltaTime: number) {
* Core.update(deltaTime);
* sceneManager.update(); // 每帧调用
* }
* ```
*/
public update(): void {
// 处理延迟场景切换
if (this._nextScene) {
this.setScene(this._nextScene);
this._nextScene = null;
}
// 更新当前场景
if (this._currentScene) {
this._currentScene.update();
}
}
/**
* 销毁场景管理器
*
* 会自动结束当前场景并清理所有资源。
* 通常在应用程序关闭时调用。
*/
public destroy(): void {
if (this._currentScene) {
this._logger.info(`Destroying scene: ${this._currentScene.name}`);
this._currentScene.end();
this._currentScene = null;
}
this._nextScene = null;
this._ecsAPI = null;
this._logger.info('SceneManager destroyed');
}
/**
* 检查是否有活跃场景
*
* @returns 如果有活跃场景返回true否则返回false
*/
public get hasScene(): boolean {
return this._currentScene !== null;
}
/**
* 检查是否有待切换的场景
*
* @returns 如果有待切换场景返回true否则返回false
*/
public get hasPendingScene(): boolean {
return this._nextScene !== null;
}
}