新增world概念(多world管理多scene概念)现在支持多个world多个scene同时更新

This commit is contained in:
YHH
2025-08-20 17:48:31 +08:00
parent 69616bbddc
commit a44251cc55
15 changed files with 3539 additions and 783 deletions

View 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;
}
}

View 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 };
}
}

View File

@@ -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';