新增world概念(多world管理多scene概念)现在支持多个world多个scene同时更新
This commit is contained in:
@@ -6,8 +6,8 @@ import { Time } from './Utils/Time';
|
||||
import { PerformanceMonitor } from './Utils/PerformanceMonitor';
|
||||
import { PoolManager } from './Utils/Pool/PoolManager';
|
||||
import { ECSFluentAPI, createECSAPI } from './ECS/Core/FluentAPI';
|
||||
import { Scene } from './ECS/Scene';
|
||||
import { IScene } from './ECS/IScene';
|
||||
import { WorldManager } from './ECS/WorldManager';
|
||||
import { DebugManager } from './Utils/Debug';
|
||||
import { ICoreConfig, IECSDebugConfig } from './Types';
|
||||
import { BigIntFactory, EnvironmentInfo } from './ECS/Utils/BigIntCompatibility';
|
||||
@@ -46,6 +46,20 @@ export class Core {
|
||||
* 当设置为true时,游戏循环将暂停执行。
|
||||
*/
|
||||
public static paused = false;
|
||||
|
||||
/**
|
||||
* 默认World ID
|
||||
*
|
||||
* 用于单Scene模式的默认World标识
|
||||
*/
|
||||
private static readonly DEFAULT_WORLD_ID = '__default__';
|
||||
|
||||
/**
|
||||
* 默认Scene ID
|
||||
*
|
||||
* 用于单Scene模式的默认Scene标识
|
||||
*/
|
||||
private static readonly DEFAULT_SCENE_ID = '__main__';
|
||||
|
||||
/**
|
||||
* 全局核心实例
|
||||
@@ -71,12 +85,6 @@ export class Core {
|
||||
*/
|
||||
public readonly debug: boolean;
|
||||
|
||||
/**
|
||||
* 待切换的场景
|
||||
*
|
||||
* 存储下一帧要切换到的场景实例。
|
||||
*/
|
||||
public _nextScene: IScene | null = null;
|
||||
|
||||
/**
|
||||
* 全局管理器集合
|
||||
@@ -113,10 +121,6 @@ export class Core {
|
||||
*/
|
||||
public _ecsAPI?: ECSFluentAPI;
|
||||
|
||||
/**
|
||||
* 当前活动场景
|
||||
*/
|
||||
public _scene?: IScene;
|
||||
|
||||
/**
|
||||
* 调试管理器
|
||||
@@ -125,6 +129,13 @@ export class Core {
|
||||
*/
|
||||
public _debugManager?: DebugManager;
|
||||
|
||||
/**
|
||||
* World管理器
|
||||
*
|
||||
* 管理多个World实例,支持多房间/多世界架构。
|
||||
*/
|
||||
public _worldManager?: WorldManager;
|
||||
|
||||
/**
|
||||
* Core配置
|
||||
*/
|
||||
@@ -194,82 +205,63 @@ export class Core {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前活动的场景
|
||||
* 获取当前活动的场景(属性访问器)
|
||||
*
|
||||
* @returns 当前场景实例,如果没有则返回null
|
||||
*/
|
||||
public static get scene(): IScene | null {
|
||||
if (!this._instance)
|
||||
return null;
|
||||
return this._instance._scene || null;
|
||||
return this.getScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前场景(已废弃)
|
||||
* 获取当前活动的场景(方法调用)
|
||||
*
|
||||
* @deprecated 请使用 Core.setScene() 方法代替。scene setter 可能导致场景延迟激活的时序问题,
|
||||
* 而 setScene() 提供更好的类型安全性和可预测的激活时序。
|
||||
*
|
||||
* 迁移示例:
|
||||
* ```typescript
|
||||
* // 旧方式(已废弃)
|
||||
* Core.scene = myScene;
|
||||
*
|
||||
* // 新方式(推荐)
|
||||
* Core.setScene(myScene);
|
||||
* ```
|
||||
*
|
||||
* 如果当前没有场景,会立即切换;否则会在下一帧切换。
|
||||
*
|
||||
* @param value - 场景实例
|
||||
* @returns 当前场景实例,如果没有则返回null
|
||||
*/
|
||||
public static set scene(value: IScene | null) {
|
||||
if (!value) return;
|
||||
|
||||
if (this._instance._scene == null) {
|
||||
this._instance.setSceneInternal(value);
|
||||
} else {
|
||||
this._instance._nextScene = value;
|
||||
public static getScene<T extends IScene>(): T | null {
|
||||
if (!this._instance) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确保默认World存在
|
||||
this._instance.ensureDefaultWorld();
|
||||
|
||||
const defaultWorld = this._instance._worldManager!.getWorld(this.DEFAULT_WORLD_ID);
|
||||
return defaultWorld?.getScene(this.DEFAULT_SCENE_ID) as T || null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 类型安全的场景设置方法(推荐)
|
||||
*
|
||||
* 这是设置场景的推荐方法,提供更好的类型安全性和可预测的激活时序。
|
||||
* 相比于 scene setter,此方法能确保场景正确初始化和激活。
|
||||
*
|
||||
* 如果当前没有场景,会立即切换;否则会在下一帧切换。
|
||||
* 设置当前场景
|
||||
*
|
||||
* @param scene - 要设置的场景实例
|
||||
* @returns 设置的场景实例,便于链式调用
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const myScene = new MyScene();
|
||||
* Core.setScene(myScene);
|
||||
*
|
||||
* // 链式调用
|
||||
* const scene = Core.setScene(new MyScene()).addSystem(new MySystem());
|
||||
* ```
|
||||
*/
|
||||
public static setScene<T extends IScene>(scene: T): T {
|
||||
if (this._instance._scene == null) {
|
||||
this._instance.setSceneInternal(scene);
|
||||
} else {
|
||||
this._instance._nextScene = scene;
|
||||
if (!this._instance) {
|
||||
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||
}
|
||||
|
||||
// 确保默认World存在
|
||||
this._instance.ensureDefaultWorld();
|
||||
|
||||
const defaultWorld = this._instance._worldManager!.getWorld(this.DEFAULT_WORLD_ID)!;
|
||||
|
||||
// 移除旧的主Scene(如果存在)
|
||||
if (defaultWorld.getScene(this.DEFAULT_SCENE_ID)) {
|
||||
defaultWorld.removeScene(this.DEFAULT_SCENE_ID);
|
||||
}
|
||||
|
||||
// 添加新Scene到默认World
|
||||
defaultWorld.createScene(this.DEFAULT_SCENE_ID, scene);
|
||||
defaultWorld.setSceneActive(this.DEFAULT_SCENE_ID, true);
|
||||
|
||||
// 触发场景切换回调
|
||||
this._instance.onSceneChanged();
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全的场景获取方法
|
||||
*
|
||||
* @returns 当前场景实例
|
||||
*/
|
||||
public static getScene<T extends IScene>(): T | null {
|
||||
return this._instance?._scene as T || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Core实例
|
||||
@@ -466,15 +458,61 @@ export class Core {
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部场景设置方法
|
||||
* 获取WorldManager实例
|
||||
*
|
||||
* @param scene - 要设置的场景实例
|
||||
* @returns WorldManager实例,如果未初始化则自动创建
|
||||
*/
|
||||
private setSceneInternal(scene: IScene): void {
|
||||
this._scene = scene;
|
||||
this.onSceneChanged();
|
||||
this._scene.initialize();
|
||||
this._scene.begin();
|
||||
public static getWorldManager(): WorldManager {
|
||||
if (!this._instance) {
|
||||
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||
}
|
||||
|
||||
if (!this._instance._worldManager) {
|
||||
// 多World模式的配置(用户主动获取WorldManager)
|
||||
this._instance._worldManager = WorldManager.getInstance({
|
||||
maxWorlds: 50,
|
||||
autoCleanup: true,
|
||||
cleanupInterval: 60000,
|
||||
debug: this._instance._config.debug
|
||||
});
|
||||
}
|
||||
|
||||
return this._instance._worldManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用World管理
|
||||
*
|
||||
* 显式启用World功能,用于多房间/多世界架构
|
||||
*/
|
||||
public static enableWorldManager(): WorldManager {
|
||||
return this.getWorldManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保默认World存在
|
||||
*
|
||||
* 内部方法,用于懒初始化默认World
|
||||
*/
|
||||
private ensureDefaultWorld(): void {
|
||||
if (!this._worldManager) {
|
||||
this._worldManager = WorldManager.getInstance({
|
||||
maxWorlds: 1, // 单场景用户只需要1个World
|
||||
autoCleanup: false, // 单场景不需要自动清理
|
||||
cleanupInterval: 0, // 禁用清理定时器
|
||||
debug: this._config.debug
|
||||
});
|
||||
}
|
||||
|
||||
// 检查默认World是否存在
|
||||
if (!this._worldManager.getWorld(Core.DEFAULT_WORLD_ID)) {
|
||||
this._worldManager.createWorld(Core.DEFAULT_WORLD_ID, {
|
||||
name: 'DefaultWorld',
|
||||
maxScenes: 1,
|
||||
autoCleanup: false
|
||||
});
|
||||
this._worldManager.setWorldActive(Core.DEFAULT_WORLD_ID, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,28 +523,19 @@ export class Core {
|
||||
public onSceneChanged() {
|
||||
Time.sceneChanged();
|
||||
|
||||
// 获取当前Scene(从默认World)
|
||||
const currentScene = Core.getScene();
|
||||
|
||||
// 初始化ECS API(如果场景支持)
|
||||
if (this._scene && this._scene.querySystem && this._scene.eventSystem) {
|
||||
this._ecsAPI = createECSAPI(this._scene, this._scene.querySystem, this._scene.eventSystem);
|
||||
if (currentScene && currentScene.querySystem && currentScene.eventSystem) {
|
||||
this._ecsAPI = createECSAPI(currentScene, currentScene.querySystem, currentScene.eventSystem);
|
||||
}
|
||||
|
||||
// 延迟调试管理器通知,避免在场景初始化过程中干扰属性
|
||||
if (this._debugManager) {
|
||||
// 使用 requestAnimationFrame 确保在场景完全初始化后再收集数据
|
||||
if (typeof requestAnimationFrame !== 'undefined') {
|
||||
requestAnimationFrame(() => {
|
||||
if (this._debugManager) {
|
||||
this._debugManager.onSceneChanged();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 兜底:使用 setTimeout
|
||||
setTimeout(() => {
|
||||
if (this._debugManager) {
|
||||
this._debugManager.onSceneChanged();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
queueMicrotask(() => {
|
||||
this._debugManager?.onSceneChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,23 +596,25 @@ export class Core {
|
||||
// 更新对象池管理器
|
||||
this._poolManager.update();
|
||||
|
||||
// 处理场景切换
|
||||
if (this._nextScene != null) {
|
||||
if (this._scene != null)
|
||||
this._scene.end();
|
||||
// 更新所有World
|
||||
if (this._worldManager) {
|
||||
const worldsStartTime = this._performanceMonitor.startMonitoring('Worlds.update');
|
||||
const activeWorlds = this._worldManager.getActiveWorlds();
|
||||
let totalWorldEntities = 0;
|
||||
|
||||
this._scene = this._nextScene;
|
||||
this._nextScene = null;
|
||||
this.onSceneChanged();
|
||||
this._scene.begin();
|
||||
}
|
||||
for (const world of activeWorlds) {
|
||||
// 更新World的全局System
|
||||
world.updateGlobalSystems();
|
||||
|
||||
// 更新World中的所有Scene
|
||||
world.updateScenes();
|
||||
|
||||
// 更新当前场景
|
||||
if (this._scene != null && this._scene.update) {
|
||||
const sceneStartTime = this._performanceMonitor.startMonitoring('Scene.update');
|
||||
this._scene.update();
|
||||
const entityCount = this._scene.entities?.count || 0;
|
||||
this._performanceMonitor.endMonitoring('Scene.update', sceneStartTime, entityCount);
|
||||
// 统计实体数量(用于性能监控)
|
||||
const worldStats = world.getStats();
|
||||
totalWorldEntities += worldStats.totalEntities;
|
||||
}
|
||||
|
||||
this._performanceMonitor.endMonitoring('Worlds.update', worldsStartTime, totalWorldEntities);
|
||||
}
|
||||
|
||||
// 更新调试管理器(基于FPS的数据发送)
|
||||
|
||||
504
packages/core/src/ECS/World.ts
Normal file
504
packages/core/src/ECS/World.ts
Normal file
@@ -0,0 +1,504 @@
|
||||
import { IScene } from './IScene';
|
||||
import { Scene } from './Scene';
|
||||
import { createLogger } from '../Utils/Logger';
|
||||
|
||||
const logger = createLogger('World');
|
||||
|
||||
/**
|
||||
* 全局系统接口
|
||||
* 全局系统是在World级别运行的系统,不依赖特定Scene
|
||||
*/
|
||||
export interface IGlobalSystem {
|
||||
/**
|
||||
* 系统名称
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* 初始化系统
|
||||
*/
|
||||
initialize?(): void;
|
||||
|
||||
/**
|
||||
* 更新系统
|
||||
*/
|
||||
update(deltaTime?: number): void;
|
||||
|
||||
/**
|
||||
* 重置系统
|
||||
*/
|
||||
reset?(): void;
|
||||
|
||||
/**
|
||||
* 销毁系统
|
||||
*/
|
||||
destroy?(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* World配置接口
|
||||
*/
|
||||
export interface IWorldConfig {
|
||||
/**
|
||||
* World名称
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* 是否启用调试模式
|
||||
*/
|
||||
debug?: boolean;
|
||||
|
||||
/**
|
||||
* 最大Scene数量限制
|
||||
*/
|
||||
maxScenes?: number;
|
||||
|
||||
/**
|
||||
* 是否自动清理空Scene
|
||||
*/
|
||||
autoCleanup?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* World类 - ECS世界管理器
|
||||
*
|
||||
* World是Scene的容器,每个World可以管理多个Scene。
|
||||
* 这种设计允许创建独立的游戏世界,如:
|
||||
* - 游戏房间(每个房间一个World)
|
||||
* - 不同的游戏模式
|
||||
* - 独立的模拟环境
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 创建游戏房间的World
|
||||
* const roomWorld = new World({ name: 'Room_001' });
|
||||
*
|
||||
* // 在World中创建Scene
|
||||
* const gameScene = roomWorld.createScene('game', new Scene());
|
||||
* const uiScene = roomWorld.createScene('ui', new Scene());
|
||||
*
|
||||
* // 更新整个World
|
||||
* roomWorld.update(deltaTime);
|
||||
* ```
|
||||
*/
|
||||
export class World {
|
||||
public readonly name: string;
|
||||
private readonly _config: IWorldConfig;
|
||||
private readonly _scenes: Map<string, IScene> = new Map();
|
||||
private readonly _activeScenes: Set<string> = new Set();
|
||||
private readonly _globalSystems: IGlobalSystem[] = [];
|
||||
private _isActive: boolean = false;
|
||||
private _createdAt: number;
|
||||
|
||||
constructor(config: IWorldConfig = {}) {
|
||||
this._config = {
|
||||
name: 'World',
|
||||
debug: false,
|
||||
maxScenes: 10,
|
||||
autoCleanup: true,
|
||||
...config
|
||||
};
|
||||
|
||||
this.name = this._config.name!;
|
||||
this._createdAt = Date.now();
|
||||
|
||||
logger.info(`创建World: ${this.name}`);
|
||||
}
|
||||
|
||||
// ===== Scene管理 =====
|
||||
|
||||
/**
|
||||
* 创建并添加Scene到World
|
||||
*/
|
||||
public createScene<T extends IScene>(sceneId: string, sceneInstance?: T): T {
|
||||
if (this._scenes.has(sceneId)) {
|
||||
throw new Error(`Scene ID '${sceneId}' 已存在于World '${this.name}' 中`);
|
||||
}
|
||||
|
||||
if (this._scenes.size >= this._config.maxScenes!) {
|
||||
throw new Error(`World '${this.name}' 已达到最大Scene数量限制: ${this._config.maxScenes}`);
|
||||
}
|
||||
|
||||
// 如果没有提供Scene实例,创建默认Scene
|
||||
const scene = sceneInstance || (new Scene() as unknown as T);
|
||||
|
||||
// 设置Scene的标识
|
||||
if ('id' in scene) {
|
||||
(scene as any).id = sceneId;
|
||||
}
|
||||
if ('name' in scene && !scene.name) {
|
||||
scene.name = sceneId;
|
||||
}
|
||||
|
||||
this._scenes.set(sceneId, scene);
|
||||
|
||||
// 初始化Scene
|
||||
scene.initialize();
|
||||
|
||||
logger.info(`在World '${this.name}' 中创建Scene: ${sceneId}`);
|
||||
return scene;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除Scene
|
||||
*/
|
||||
public removeScene(sceneId: string): boolean {
|
||||
const scene = this._scenes.get(sceneId);
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果Scene正在运行,先停止它
|
||||
if (this._activeScenes.has(sceneId)) {
|
||||
this.setSceneActive(sceneId, false);
|
||||
}
|
||||
|
||||
// 清理Scene资源
|
||||
scene.end();
|
||||
this._scenes.delete(sceneId);
|
||||
|
||||
logger.info(`从World '${this.name}' 中移除Scene: ${sceneId}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Scene
|
||||
*/
|
||||
public getScene<T extends IScene>(sceneId: string): T | null {
|
||||
return this._scenes.get(sceneId) as T || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有Scene ID
|
||||
*/
|
||||
public getSceneIds(): string[] {
|
||||
return Array.from(this._scenes.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有Scene
|
||||
*/
|
||||
public getAllScenes(): IScene[] {
|
||||
return Array.from(this._scenes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Scene激活状态
|
||||
*/
|
||||
public setSceneActive(sceneId: string, active: boolean): void {
|
||||
const scene = this._scenes.get(sceneId);
|
||||
if (!scene) {
|
||||
logger.warn(`Scene '${sceneId}' 不存在于World '${this.name}' 中`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
this._activeScenes.add(sceneId);
|
||||
// 启动Scene
|
||||
if (scene.begin) {
|
||||
scene.begin();
|
||||
}
|
||||
logger.debug(`在World '${this.name}' 中激活Scene: ${sceneId}`);
|
||||
} else {
|
||||
this._activeScenes.delete(sceneId);
|
||||
// 可选择性地停止Scene,或者让它继续运行但不更新
|
||||
logger.debug(`在World '${this.name}' 中停用Scene: ${sceneId}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查Scene是否激活
|
||||
*/
|
||||
public isSceneActive(sceneId: string): boolean {
|
||||
return this._activeScenes.has(sceneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活跃Scene数量
|
||||
*/
|
||||
public getActiveSceneCount(): number {
|
||||
return this._activeScenes.size;
|
||||
}
|
||||
|
||||
// ===== 全局System管理 =====
|
||||
|
||||
/**
|
||||
* 添加全局System
|
||||
* 全局System会在所有激活Scene之前更新
|
||||
*/
|
||||
public addGlobalSystem<T extends IGlobalSystem>(system: T): T {
|
||||
if (this._globalSystems.includes(system)) {
|
||||
return system;
|
||||
}
|
||||
|
||||
this._globalSystems.push(system);
|
||||
if (system.initialize) {
|
||||
system.initialize();
|
||||
}
|
||||
|
||||
logger.debug(`在World '${this.name}' 中添加全局System: ${system.name}`);
|
||||
return system;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除全局System
|
||||
*/
|
||||
public removeGlobalSystem(system: IGlobalSystem): boolean {
|
||||
const index = this._globalSystems.indexOf(system);
|
||||
if (index === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._globalSystems.splice(index, 1);
|
||||
if (system.reset) {
|
||||
system.reset();
|
||||
}
|
||||
|
||||
logger.debug(`从World '${this.name}' 中移除全局System: ${system.name}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局System
|
||||
*/
|
||||
public getGlobalSystem<T extends IGlobalSystem>(type: new (...args: any[]) => T): T | null {
|
||||
for (const system of this._globalSystems) {
|
||||
if (system instanceof type) {
|
||||
return system as T;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ===== World生命周期 =====
|
||||
|
||||
/**
|
||||
* 启动World
|
||||
*/
|
||||
public start(): void {
|
||||
if (this._isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isActive = true;
|
||||
|
||||
// 启动所有全局System
|
||||
for (const system of this._globalSystems) {
|
||||
if (system.initialize) {
|
||||
system.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`启动World: ${this.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止World
|
||||
*/
|
||||
public stop(): void {
|
||||
if (!this._isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 停止所有Scene
|
||||
for (const sceneId of this._activeScenes) {
|
||||
this.setSceneActive(sceneId, false);
|
||||
}
|
||||
|
||||
// 重置所有全局System
|
||||
for (const system of this._globalSystems) {
|
||||
if (system.reset) {
|
||||
system.reset();
|
||||
}
|
||||
}
|
||||
|
||||
this._isActive = false;
|
||||
logger.info(`停止World: ${this.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新World中的全局System
|
||||
* 注意:此方法由Core.update()调用,不应直接调用
|
||||
*/
|
||||
public updateGlobalSystems(): void {
|
||||
if (!this._isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新全局System
|
||||
for (const system of this._globalSystems) {
|
||||
if (system.update) {
|
||||
system.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新World中的所有激活Scene
|
||||
* 注意:此方法由Core.update()调用,不应直接调用
|
||||
*/
|
||||
public updateScenes(): void {
|
||||
if (!this._isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新所有激活的Scene
|
||||
for (const sceneId of this._activeScenes) {
|
||||
const scene = this._scenes.get(sceneId);
|
||||
if (scene && scene.update) {
|
||||
scene.update();
|
||||
}
|
||||
}
|
||||
|
||||
// 自动清理(如果启用)
|
||||
if (this._config.autoCleanup && this.shouldAutoCleanup()) {
|
||||
this.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁World
|
||||
*/
|
||||
public destroy(): void {
|
||||
logger.info(`销毁World: ${this.name}`);
|
||||
|
||||
// 停止World
|
||||
this.stop();
|
||||
|
||||
// 销毁所有Scene
|
||||
const sceneIds = Array.from(this._scenes.keys());
|
||||
for (const sceneId of sceneIds) {
|
||||
this.removeScene(sceneId);
|
||||
}
|
||||
|
||||
// 清理全局System
|
||||
for (const system of this._globalSystems) {
|
||||
if (system.destroy) {
|
||||
system.destroy();
|
||||
} else if (system.reset) {
|
||||
system.reset();
|
||||
}
|
||||
}
|
||||
this._globalSystems.length = 0;
|
||||
|
||||
this._scenes.clear();
|
||||
this._activeScenes.clear();
|
||||
}
|
||||
|
||||
// ===== 状态信息 =====
|
||||
|
||||
/**
|
||||
* 获取World状态
|
||||
*/
|
||||
public getStatus() {
|
||||
return {
|
||||
name: this.name,
|
||||
isActive: this._isActive,
|
||||
sceneCount: this._scenes.size,
|
||||
activeSceneCount: this._activeScenes.size,
|
||||
globalSystemCount: this._globalSystems.length,
|
||||
createdAt: this._createdAt,
|
||||
config: { ...this._config },
|
||||
scenes: Array.from(this._scenes.keys()).map(sceneId => ({
|
||||
id: sceneId,
|
||||
isActive: this._activeScenes.has(sceneId),
|
||||
name: this._scenes.get(sceneId)?.name || sceneId
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取World统计信息
|
||||
*/
|
||||
public getStats() {
|
||||
const stats = {
|
||||
totalEntities: 0,
|
||||
totalSystems: this._globalSystems.length,
|
||||
memoryUsage: 0,
|
||||
performance: {
|
||||
averageUpdateTime: 0,
|
||||
maxUpdateTime: 0
|
||||
}
|
||||
};
|
||||
|
||||
// 统计所有Scene的实体数量
|
||||
for (const scene of this._scenes.values()) {
|
||||
if (scene.entities) {
|
||||
stats.totalEntities += scene.entities.count;
|
||||
}
|
||||
if (scene.systems) {
|
||||
stats.totalSystems += scene.systems.length;
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
// ===== 私有方法 =====
|
||||
|
||||
/**
|
||||
* 检查是否应该执行自动清理
|
||||
*/
|
||||
private shouldAutoCleanup(): boolean {
|
||||
// 简单的清理策略:如果有空Scene且超过5分钟没有实体
|
||||
const currentTime = Date.now();
|
||||
const cleanupThreshold = 5 * 60 * 1000; // 5分钟
|
||||
|
||||
for (const [sceneId, scene] of this._scenes) {
|
||||
if (!this._activeScenes.has(sceneId) &&
|
||||
scene.entities &&
|
||||
scene.entities.count === 0 &&
|
||||
(currentTime - this._createdAt) > cleanupThreshold) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行清理操作
|
||||
*/
|
||||
private cleanup(): void {
|
||||
const sceneIds = Array.from(this._scenes.keys());
|
||||
const currentTime = Date.now();
|
||||
const cleanupThreshold = 5 * 60 * 1000; // 5分钟
|
||||
|
||||
for (const sceneId of sceneIds) {
|
||||
const scene = this._scenes.get(sceneId);
|
||||
if (scene &&
|
||||
!this._activeScenes.has(sceneId) &&
|
||||
scene.entities &&
|
||||
scene.entities.count === 0 &&
|
||||
(currentTime - this._createdAt) > cleanupThreshold) {
|
||||
|
||||
this.removeScene(sceneId);
|
||||
logger.debug(`自动清理空Scene: ${sceneId} from World ${this.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 访问器 =====
|
||||
|
||||
/**
|
||||
* 检查World是否激活
|
||||
*/
|
||||
public get isActive(): boolean {
|
||||
return this._isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Scene数量
|
||||
*/
|
||||
public get sceneCount(): number {
|
||||
return this._scenes.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取创建时间
|
||||
*/
|
||||
public get createdAt(): number {
|
||||
return this._createdAt;
|
||||
}
|
||||
}
|
||||
463
packages/core/src/ECS/WorldManager.ts
Normal file
463
packages/core/src/ECS/WorldManager.ts
Normal file
@@ -0,0 +1,463 @@
|
||||
import { World, IWorldConfig } from './World';
|
||||
import { createLogger } from '../Utils/Logger';
|
||||
|
||||
const logger = createLogger('WorldManager');
|
||||
|
||||
/**
|
||||
* WorldManager配置接口
|
||||
*/
|
||||
export interface IWorldManagerConfig {
|
||||
/**
|
||||
* 最大World数量
|
||||
*/
|
||||
maxWorlds?: number;
|
||||
|
||||
/**
|
||||
* 是否自动清理空World
|
||||
*/
|
||||
autoCleanup?: boolean;
|
||||
|
||||
/**
|
||||
* 清理间隔(毫秒)
|
||||
*/
|
||||
cleanupInterval?: number;
|
||||
|
||||
/**
|
||||
* 是否启用调试模式
|
||||
*/
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* World管理器 - 管理所有World实例
|
||||
*
|
||||
* WorldManager是全局单例,负责管理所有World的生命周期。
|
||||
* 每个World都是独立的ECS环境,可以包含多个Scene。
|
||||
*
|
||||
* 设计理念:
|
||||
* - Core负责单Scene的传统ECS管理
|
||||
* - World负责多Scene的管理和协调
|
||||
* - WorldManager负责多World的全局管理
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 获取全局WorldManager
|
||||
* const worldManager = WorldManager.getInstance();
|
||||
*
|
||||
* // 创建游戏房间World
|
||||
* const roomWorld = worldManager.createWorld('room_001', {
|
||||
* name: 'GameRoom_001',
|
||||
* maxScenes: 5
|
||||
* });
|
||||
*
|
||||
* // 在游戏循环中更新所有World
|
||||
* worldManager.updateAll(deltaTime);
|
||||
* ```
|
||||
*/
|
||||
export class WorldManager {
|
||||
private static _instance: WorldManager | null = null;
|
||||
|
||||
private readonly _config: IWorldManagerConfig;
|
||||
private readonly _worlds: Map<string, World> = new Map();
|
||||
private readonly _activeWorlds: Set<string> = new Set();
|
||||
private _cleanupTimer: NodeJS.Timeout | null = null;
|
||||
private _isRunning: boolean = false;
|
||||
|
||||
private constructor(config: IWorldManagerConfig = {}) {
|
||||
this._config = {
|
||||
maxWorlds: 50,
|
||||
autoCleanup: true,
|
||||
cleanupInterval: 30000, // 30秒
|
||||
debug: false,
|
||||
...config
|
||||
};
|
||||
|
||||
logger.info('WorldManager已初始化', {
|
||||
maxWorlds: this._config.maxWorlds,
|
||||
autoCleanup: this._config.autoCleanup,
|
||||
cleanupInterval: this._config.cleanupInterval
|
||||
});
|
||||
|
||||
this.startCleanupTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取WorldManager单例实例
|
||||
*/
|
||||
public static getInstance(config?: IWorldManagerConfig): WorldManager {
|
||||
if (!this._instance) {
|
||||
this._instance = new WorldManager(config);
|
||||
}
|
||||
return this._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置WorldManager实例(主要用于测试)
|
||||
*/
|
||||
public static reset(): void {
|
||||
if (this._instance) {
|
||||
this._instance.destroy();
|
||||
this._instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== World管理 =====
|
||||
|
||||
/**
|
||||
* 创建新World
|
||||
*/
|
||||
public createWorld(worldId: string, config?: IWorldConfig): World {
|
||||
if (!worldId || typeof worldId !== 'string' || worldId.trim() === '') {
|
||||
throw new Error('World ID不能为空');
|
||||
}
|
||||
|
||||
if (this._worlds.has(worldId)) {
|
||||
throw new Error(`World ID '${worldId}' 已存在`);
|
||||
}
|
||||
|
||||
if (this._worlds.size >= this._config.maxWorlds!) {
|
||||
throw new Error(`已达到最大World数量限制: ${this._config.maxWorlds}`);
|
||||
}
|
||||
|
||||
const worldConfig: IWorldConfig = {
|
||||
name: worldId,
|
||||
debug: this._config.debug,
|
||||
...config
|
||||
};
|
||||
|
||||
const world = new World(worldConfig);
|
||||
this._worlds.set(worldId, world);
|
||||
|
||||
logger.info(`创建World: ${worldId}`, { config: worldConfig });
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除World
|
||||
*/
|
||||
public removeWorld(worldId: string): boolean {
|
||||
const world = this._worlds.get(worldId);
|
||||
if (!world) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果World正在运行,先停止它
|
||||
if (this._activeWorlds.has(worldId)) {
|
||||
this.setWorldActive(worldId, false);
|
||||
}
|
||||
|
||||
// 销毁World
|
||||
world.destroy();
|
||||
this._worlds.delete(worldId);
|
||||
|
||||
logger.info(`移除World: ${worldId}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取World
|
||||
*/
|
||||
public getWorld(worldId: string): World | null {
|
||||
return this._worlds.get(worldId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有World ID
|
||||
*/
|
||||
public getWorldIds(): string[] {
|
||||
return Array.from(this._worlds.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有World
|
||||
*/
|
||||
public getAllWorlds(): World[] {
|
||||
return Array.from(this._worlds.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置World激活状态
|
||||
*/
|
||||
public setWorldActive(worldId: string, active: boolean): void {
|
||||
const world = this._worlds.get(worldId);
|
||||
if (!world) {
|
||||
logger.warn(`World '${worldId}' 不存在`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
this._activeWorlds.add(worldId);
|
||||
world.start();
|
||||
logger.debug(`激活World: ${worldId}`);
|
||||
} else {
|
||||
this._activeWorlds.delete(worldId);
|
||||
world.stop();
|
||||
logger.debug(`停用World: ${worldId}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查World是否激活
|
||||
*/
|
||||
public isWorldActive(worldId: string): boolean {
|
||||
return this._activeWorlds.has(worldId);
|
||||
}
|
||||
|
||||
// ===== 批量操作 =====
|
||||
|
||||
/**
|
||||
* 获取所有激活的World
|
||||
* 注意:此方法供Core.update()使用
|
||||
*/
|
||||
public getActiveWorlds(): World[] {
|
||||
const activeWorlds: World[] = [];
|
||||
for (const worldId of this._activeWorlds) {
|
||||
const world = this._worlds.get(worldId);
|
||||
if (world) {
|
||||
activeWorlds.push(world);
|
||||
}
|
||||
}
|
||||
return activeWorlds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动所有World
|
||||
*/
|
||||
public startAll(): void {
|
||||
this._isRunning = true;
|
||||
|
||||
for (const worldId of this._worlds.keys()) {
|
||||
this.setWorldActive(worldId, true);
|
||||
}
|
||||
|
||||
logger.info('启动所有World');
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有World
|
||||
*/
|
||||
public stopAll(): void {
|
||||
this._isRunning = false;
|
||||
|
||||
for (const worldId of this._activeWorlds) {
|
||||
this.setWorldActive(worldId, false);
|
||||
}
|
||||
|
||||
logger.info('停止所有World');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找满足条件的World
|
||||
*/
|
||||
public findWorlds(predicate: (world: World) => boolean): World[] {
|
||||
const results: World[] = [];
|
||||
for (const world of this._worlds.values()) {
|
||||
if (predicate(world)) {
|
||||
results.push(world);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称查找World
|
||||
*/
|
||||
public findWorldByName(name: string): World | null {
|
||||
for (const world of this._worlds.values()) {
|
||||
if (world.name === name) {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ===== 统计和监控 =====
|
||||
|
||||
/**
|
||||
* 获取WorldManager统计信息
|
||||
*/
|
||||
public getStats() {
|
||||
const stats = {
|
||||
totalWorlds: this._worlds.size,
|
||||
activeWorlds: this._activeWorlds.size,
|
||||
totalScenes: 0,
|
||||
totalEntities: 0,
|
||||
totalSystems: 0,
|
||||
memoryUsage: 0,
|
||||
isRunning: this._isRunning,
|
||||
config: { ...this._config },
|
||||
worlds: [] as any[]
|
||||
};
|
||||
|
||||
for (const [worldId, world] of this._worlds) {
|
||||
const worldStats = world.getStats();
|
||||
stats.totalScenes += worldStats.totalSystems; // World的getStats可能需要调整
|
||||
stats.totalEntities += worldStats.totalEntities;
|
||||
stats.totalSystems += worldStats.totalSystems;
|
||||
|
||||
stats.worlds.push({
|
||||
id: worldId,
|
||||
name: world.name,
|
||||
isActive: this._activeWorlds.has(worldId),
|
||||
sceneCount: world.sceneCount,
|
||||
...worldStats
|
||||
});
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取详细状态信息
|
||||
*/
|
||||
public getDetailedStatus() {
|
||||
return {
|
||||
...this.getStats(),
|
||||
worlds: Array.from(this._worlds.entries()).map(([worldId, world]) => ({
|
||||
id: worldId,
|
||||
isActive: this._activeWorlds.has(worldId),
|
||||
status: world.getStatus()
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
// ===== 生命周期管理 =====
|
||||
|
||||
/**
|
||||
* 清理空World
|
||||
*/
|
||||
public cleanup(): number {
|
||||
const worldsToRemove: string[] = [];
|
||||
|
||||
for (const [worldId, world] of this._worlds) {
|
||||
if (this.shouldCleanupWorld(world)) {
|
||||
worldsToRemove.push(worldId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const worldId of worldsToRemove) {
|
||||
this.removeWorld(worldId);
|
||||
}
|
||||
|
||||
if (worldsToRemove.length > 0) {
|
||||
logger.debug(`清理了 ${worldsToRemove.length} 个World`);
|
||||
}
|
||||
|
||||
return worldsToRemove.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁WorldManager
|
||||
*/
|
||||
public destroy(): void {
|
||||
logger.info('正在销毁WorldManager...');
|
||||
|
||||
// 停止清理定时器
|
||||
this.stopCleanupTimer();
|
||||
|
||||
// 停止所有World
|
||||
this.stopAll();
|
||||
|
||||
// 销毁所有World
|
||||
const worldIds = Array.from(this._worlds.keys());
|
||||
for (const worldId of worldIds) {
|
||||
this.removeWorld(worldId);
|
||||
}
|
||||
|
||||
this._worlds.clear();
|
||||
this._activeWorlds.clear();
|
||||
this._isRunning = false;
|
||||
|
||||
logger.info('WorldManager已销毁');
|
||||
}
|
||||
|
||||
// ===== 私有方法 =====
|
||||
|
||||
/**
|
||||
* 启动清理定时器
|
||||
*/
|
||||
private startCleanupTimer(): void {
|
||||
if (!this._config.autoCleanup || this._cleanupTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._cleanupTimer = setInterval(() => {
|
||||
this.cleanup();
|
||||
}, this._config.cleanupInterval);
|
||||
|
||||
logger.debug(`启动World清理定时器,间隔: ${this._config.cleanupInterval}ms`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止清理定时器
|
||||
*/
|
||||
private stopCleanupTimer(): void {
|
||||
if (this._cleanupTimer) {
|
||||
clearInterval(this._cleanupTimer);
|
||||
this._cleanupTimer = null;
|
||||
logger.debug('停止World清理定时器');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断World是否应该被清理
|
||||
*/
|
||||
private shouldCleanupWorld(world: World): boolean {
|
||||
// 清理策略:
|
||||
// 1. World未激活
|
||||
// 2. 没有Scene或所有Scene都是空的
|
||||
// 3. 创建时间超过10分钟
|
||||
|
||||
if (world.isActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (world.sceneCount === 0) {
|
||||
const age = Date.now() - world.createdAt;
|
||||
return age > 10 * 60 * 1000; // 10分钟
|
||||
}
|
||||
|
||||
// 检查是否所有Scene都是空的
|
||||
const allScenes = world.getAllScenes();
|
||||
const hasEntities = allScenes.some(scene =>
|
||||
scene.entities && scene.entities.count > 0
|
||||
);
|
||||
|
||||
if (!hasEntities) {
|
||||
const age = Date.now() - world.createdAt;
|
||||
return age > 10 * 60 * 1000; // 10分钟
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===== 访问器 =====
|
||||
|
||||
/**
|
||||
* 获取World总数
|
||||
*/
|
||||
public get worldCount(): number {
|
||||
return this._worlds.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取激活World数量
|
||||
*/
|
||||
public get activeWorldCount(): number {
|
||||
return this._activeWorlds.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否正在运行
|
||||
*/
|
||||
public get isRunning(): boolean {
|
||||
return this._isRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
*/
|
||||
public get config(): IWorldManagerConfig {
|
||||
return { ...this._config };
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ export * from './Utils';
|
||||
export * from './Decorators';
|
||||
export { Scene } from './Scene';
|
||||
export { IScene, ISceneFactory, ISceneConfig } from './IScene';
|
||||
export { World, IWorldConfig } from './World';
|
||||
export { WorldManager, IWorldManagerConfig } from './WorldManager';
|
||||
export { EntityManager, EntityQueryBuilder } from './Core/EntityManager';
|
||||
export * from './Core/Events';
|
||||
export * from './Core/Query';
|
||||
|
||||
Reference in New Issue
Block a user