新增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

@@ -264,22 +264,17 @@ player.addComponent(new Velocity(50, 30)); // 每秒移动 50 像素x方向
player.addComponent(new Sprite("player.png", 64, 64));
```
## World 概念
## 场景管理
World 是 Scene 的容器,用于管理多个独立的游戏世界。这种设计特别适用于
- 多人游戏房间(每个房间一个 World
- 不同的游戏模式
- 独立的模拟环境
### 基本用法
Core 内置了场景管理功能,使用非常简单
```typescript
import { World, Scene } from '@esengine/ecs-framework'
import { Core, Scene } from '@esengine/ecs-framework';
// 创建游戏房间的World
const roomWorld = new World({ name: 'Room_001' });
// 初始化Core
Core.create({ debug: true });
// 在World中创建多个Scene
// 创建并设置场景
class GameScene extends Scene {
initialize(): void {
this.name = "GamePlay";
@@ -288,78 +283,106 @@ class GameScene extends Scene {
}
}
class UIScene extends Scene {
initialize(): void {
this.name = "UI";
// UI相关系统
}
const gameScene = new GameScene();
Core.setScene(gameScene);
// 游戏循环(自动更新场景)
function gameLoop(deltaTime: number) {
Core.update(deltaTime); // 自动更新全局服务和场景
}
// 添加Scene到World
const gameScene = roomWorld.createScene('game', new GameScene());
const uiScene = roomWorld.createScene('ui', new UIScene());
// 切换场景
Core.loadScene(new MenuScene()); // 延迟切换(下一帧)
Core.setScene(new GameScene()); // 立即切换
// 激活Scene
roomWorld.setSceneActive('game', true);
roomWorld.setSceneActive('ui', true);
// 访问当前场景
const currentScene = Core.scene;
// 启动World
roomWorld.start();
// 使用流式API
const player = Core.ecsAPI?.createEntity('Player')
.addComponent(Position, 100, 100)
.addComponent(Velocity, 50, 0);
```
### World 生命周期
### 高级:使用 WorldManager 管理多世界
World 提供了完整的生命周期管理
- `start()`: 启动 World 和所有全局系统
- `updateGlobalSystems()`: 更新全局系统(由 Core.update() 调用)
- `updateScenes()`: 更新所有激活的 Scene由 Core.update() 调用)
- `stop()`: 停止 World
- `destroy()`: 销毁 World 和所有资源
仅适用于复杂的服务器端应用MMO游戏服务器、游戏房间系统等
```typescript
import { Core, WorldManager } from '@esengine/ecs-framework';
// 初始化Core
Core.create({ debug: true });
// 创建世界管理器(手动管理)
const worldManager = new WorldManager();
// 创建多个独立的游戏世界
const room1 = worldManager.createWorld('room_001');
const room2 = worldManager.createWorld('room_002');
// 在每个世界中创建场景
const gameScene1 = room1.createScene('game', new GameScene());
const gameScene2 = room2.createScene('game', new GameScene());
// 激活场景
room1.setSceneActive('game', true);
room2.setSceneActive('game', true);
// 游戏循环(需要手动更新世界)
function gameLoop(deltaTime: number) {
Core.update(deltaTime); // 更新全局服务
worldManager.updateAll(); // 手动更新所有世界
}
```
## 与游戏引擎集成
### Laya 引擎集成
```typescript
import { Stage } from "laya/display/Stage"
import { Stat } from "laya/utils/Stat"
import { Laya } from "Laya"
import { Stage } from "laya/display/Stage";
import { Laya } from "Laya";
import { Core } from '@esengine/ecs-framework';
// 初始化 Laya
Laya.init(800, 600).then(() => {
// 初始化 ECS
const core = Core.create(true)
// 设置场景...
Core.create(true);
Core.setScene(new GameScene());
// 启动游戏循环
Laya.timer.frameLoop(1, this, () => {
const deltaTime = Laya.timer.delta / 1000 // 转换为秒
Core.update(deltaTime)
})
})
const deltaTime = Laya.timer.delta / 1000;
Core.update(deltaTime); // 自动更新全局服务和场景
});
});
```
### Cocos Creator 集成
```typescript
import { Component, _decorator } from 'cc'
import { Component, _decorator } from 'cc';
import { Core } from '@esengine/ecs-framework';
const { ccclass } = _decorator
const { ccclass } = _decorator;
@ccclass('ECSGameManager')
export class ECSGameManager extends Component {
onLoad() {
// 初始化 ECS
const core = Core.create(true)
// 设置场景...
Core.create(true);
Core.setScene(new GameScene());
}
update(deltaTime: number) {
// 更新 ECS
Core.update(deltaTime)
// 自动更新全局服务和场景
Core.update(deltaTime);
}
onDestroy() {
// 清理资源
Core.destroy();
}
}
```
@@ -378,7 +401,7 @@ export class ECSGameManager extends Component {
确保:
1. 系统已添加到场景:`this.addSystem(system)` (在 Scene 的 initialize 方法中)
2. 场景已设置为当前场景`Core.setScene(scene)`
2. 场景已设置:`Core.setScene(scene)`
3. 游戏循环在调用:`Core.update(deltaTime)`
### 如何调试 ECS 应用?

View File

@@ -289,12 +289,20 @@ class StatsScene extends Scene {
## 场景集成到框架
场景可以通过两种方式运行
ECS Framework 提供了灵活的场景管理架构,适用于不同规模的应用
### 1. 简单的单场景应用
### 1. 使用 SceneManager推荐大多数应用
适用于 95% 的游戏应用(单人游戏、简单多人游戏、移动游戏等):
```typescript
import { Core } from '@esengine/ecs-framework';
import { Core, SceneManager } from '@esengine/ecs-framework';
// 初始化Core全局服务
Core.create({ debug: true });
// 创建场景管理器
const sceneManager = new SceneManager();
// 创建游戏场景
class GameScene extends Scene {
@@ -305,21 +313,52 @@ class GameScene extends Scene {
}
}
// 启动游戏
Core.create();
// 设置场景
const gameScene = new GameScene();
Core.setScene(gameScene);
sceneManager.setScene(gameScene);
// 游戏循环
function gameLoop(deltaTime: number) {
Core.update(deltaTime); // 更新全局服务
sceneManager.update(); // 更新当前场景
}
```
### 2. 复杂的多场景应用
### 2. 场景切换
SceneManager 支持流畅的场景切换:
```typescript
import { WorldManager } from '@esengine/ecs-framework';
// 立即切换场景
const menuScene = new MenuScene();
sceneManager.setScene(menuScene);
// 获取WorldManager实例
const worldManager = WorldManager.getInstance();
// 延迟切换场景(在下一帧切换)
const gameScene = new GameScene();
sceneManager.startSceneTransition(gameScene, false);
// 创建World
// 访问当前场景
const currentScene = sceneManager.currentScene;
// 访问 ECS API
const ecsAPI = sceneManager.ecsAPI;
const entity = ecsAPI?.createEntity('player');
```
### 3. 使用 WorldManager高级用例
适用于需要完全隔离的多世界应用MMO服务器、游戏房间系统等
```typescript
import { Core, WorldManager } from '@esengine/ecs-framework';
// 初始化Core全局服务
Core.create({ debug: true });
// 创建世界管理器
const worldManager = new WorldManager();
// 创建多个独立的游戏世界
const gameWorld = worldManager.createWorld('game', {
name: 'MainGame',
maxScenes: 5
@@ -331,6 +370,12 @@ const gameScene = gameWorld.createScene('game', new GameScene());
// 激活场景
gameWorld.setSceneActive('menu', true);
// 游戏循环
function gameLoop(deltaTime: number) {
Core.update(deltaTime); // 更新全局服务
worldManager.updateAll(); // 更新所有世界
}
```
## 多场景管理
@@ -376,21 +421,43 @@ class GameWorld extends World {
}
```
## 与 World 的关系
## 架构层次
Scene 的运行架构层次
ECS Framework 的架构层次清晰,职责分明
```typescript
// Core -> WorldManager -> World -> Scene -> EntitySystem -> Entity -> Component
// 架构层次:
// Core (全局服务) → SceneManager (场景管理) → Scene → EntitySystem → Entity → Component
// 或
// Core (全局服务) → WorldManager (世界管理) → World → Scene → EntitySystem → Entity → Component
// 1. 简单应用Core直接管理单个Scene
Core.setScene(new GameScene());
// 1. 推荐:使用 SceneManager 管理单场景/场景切换
import { Core, SceneManager } from '@esengine/ecs-framework';
// 2. 复杂应用WorldManager管理多个World每个World管理多个Scene
const worldManager = WorldManager.getInstance();
Core.create({ debug: true });
const sceneManager = new SceneManager();
sceneManager.setScene(new GameScene());
// 游戏循环
function gameLoop(deltaTime: number) {
Core.update(deltaTime); // 全局服务
sceneManager.update(); // 场景更新
}
// 2. 高级:使用 WorldManager 管理多世界
import { Core, WorldManager } from '@esengine/ecs-framework';
Core.create({ debug: true });
const worldManager = new WorldManager();
const world = worldManager.createWorld('gameWorld');
const scene = world.createScene('mainScene', new GameScene());
world.setSceneActive('mainScene', true);
// 游戏循环
function gameLoop(deltaTime: number) {
Core.update(deltaTime); // 全局服务
worldManager.updateAll(); // 所有世界更新
}
```
## 最佳实践

View File

@@ -5,37 +5,43 @@ import { Timer } from './Utils/Timers/Timer';
import { Time } from './Utils/Time';
import { PerformanceMonitor } from './Utils/PerformanceMonitor';
import { PoolManager } from './Utils/Pool/PoolManager';
import { ECSFluentAPI, createECSAPI } from './ECS/Core/FluentAPI';
import { IScene } from './ECS/IScene';
import { WorldManager, IWorldManagerConfig } from './ECS/WorldManager';
import { DebugManager } from './Utils/Debug';
import { ICoreConfig, IECSDebugConfig } from './Types';
import { createLogger } from './Utils/Logger';
import { SceneManager } from './ECS/SceneManager';
import { IScene } from './ECS/IScene';
/**
* 游戏引擎核心类
*
* 负责管理游戏的生命周期、场景切换、全局管理器和定时器系统。
* 提供统一的游戏循环管理。
* 职责:
* - 提供全局服务Timer、Performance、Pool等
* - 管理场景生命周期内置SceneManager
* - 管理全局管理器的生命周期
* - 提供统一的游戏循环更新入口
*
* @example
* ```typescript
* // 创建核心实例
* const core = Core.create(true);
* // 初始化并设置场景
* Core.create({ debug: true });
* Core.setScene(new GameScene());
*
* // 设置场景
* Core.scene = new MyScene();
*
* // 在游戏循环中更新Laya引擎示例
* Laya.timer.frameLoop(1, this, () => {
* const deltaTime = Laya.timer.delta / 1000;
* // 游戏循环(自动更新全局服务和场景
* function gameLoop(deltaTime: number) {
* Core.update(deltaTime);
* }
*
* // 使用定时器
* Core.schedule(1.0, false, null, (timer) => {
* console.log("1秒后执行");
* });
*
* // 调度定时器
* Core.schedule(1.0, false, null, (timer) => {
* Core._logger.info("1秒后执行");
* });
* // 切换场景
* Core.loadScene(new MenuScene()); // 延迟切换
* Core.setScene(new GameScene()); // 立即切换
*
* // 获取当前场景
* const currentScene = Core.scene;
* ```
*/
export class Core {
@@ -46,20 +52,6 @@ export class Core {
*/
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__';
/**
* 全局核心实例
*/
@@ -84,7 +76,6 @@ export class Core {
*/
public readonly debug: boolean;
/**
* 全局管理器集合
*
@@ -113,14 +104,6 @@ export class Core {
*/
public _poolManager: PoolManager;
/**
* ECS流式API
*
* 提供便捷的ECS操作接口。
*/
public _ecsAPI?: ECSFluentAPI;
/**
* 调试管理器
*
@@ -129,18 +112,17 @@ export class Core {
public _debugManager?: DebugManager;
/**
* World管理器
* 场景管理器
*
* 管理多个World实例支持多房间/多世界架构
* 管理当前场景的生命周期
*/
public _worldManager?: WorldManager;
private _sceneManager: SceneManager;
/**
* Core配置
*/
private _config: ICoreConfig;
/**
* 创建核心实例
*
@@ -156,8 +138,7 @@ export class Core {
...config
};
// 初始化管理器
// 初始化定时器管理器
this._timerManager = new TimerManager();
Core.registerGlobalManager(this._timerManager);
@@ -172,6 +153,9 @@ export class Core {
// 初始化对象池管理器
this._poolManager = PoolManager.getInstance();
// 初始化场景管理器
this._sceneManager = new SceneManager();
Core.entitySystemsEnabled = this._config.enableEntitySystems ?? true;
this.debug = this._config.debug ?? true;
@@ -180,7 +164,6 @@ export class Core {
this._debugManager = new DebugManager(this, this._config.debugConfig);
}
this.initialize();
}
@@ -193,65 +176,6 @@ export class Core {
return this._instance;
}
/**
* 获取当前活动的场景(属性访问器)
*
* @returns 当前场景实例如果没有则返回null
*/
public static get scene(): IScene | null {
return this.getScene();
}
/**
* 获取当前活动的场景(方法调用)
*
* @returns 当前场景实例如果没有则返回null
*/
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;
}
/**
* 设置当前场景
*
* @param scene - 要设置的场景实例
* @returns 设置的场景实例,便于链式调用
*/
public static setScene<T extends IScene>(scene: T): T {
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;
}
/**
* 创建Core实例
*
@@ -259,6 +183,22 @@ export class Core {
*
* @param config - Core配置也可以直接传入boolean表示debug模式向后兼容
* @returns Core实例
*
* @example
* ```typescript
* // 方式1使用配置对象
* Core.create({
* debug: true,
* enableEntitySystems: true,
* debugConfig: {
* enabled: true,
* websocketUrl: 'ws://localhost:9229'
* }
* });
*
* // 方式2简单模式向后兼容
* Core.create(true); // debug = true
* ```
*/
public static create(config: ICoreConfig | boolean = true): Core {
if (this._instance == null) {
@@ -267,31 +207,118 @@ export class Core {
? { debug: config, enableEntitySystems: true }
: config;
this._instance = new Core(coreConfig);
} else {
this._logger.warn('Core实例已创建返回现有实例');
}
return this._instance;
}
/**
* 设置当前场景
*
* @param scene - 要设置的场景
* @returns 设置的场景实例
*
* @example
* ```typescript
* Core.create({ debug: true });
*
* // 创建并设置场景
* const gameScene = new GameScene();
* Core.setScene(gameScene);
* ```
*/
public static setScene<T extends IScene>(scene: T): T {
if (!this._instance) {
Core._logger.warn("Core实例未创建请先调用Core.create()");
throw new Error("Core实例未创建");
}
return this._instance._sceneManager.setScene(scene);
}
/**
* 获取当前场景
*
* @returns 当前场景如果没有场景则返回null
*/
public static get scene(): IScene | null {
if (!this._instance) {
return null;
}
return this._instance._sceneManager.currentScene;
}
/**
* 获取ECS流式API
*
* @returns ECS API实例如果当前没有场景则返回null
*
* @example
* ```typescript
* // 使用流式API创建实体
* const player = Core.ecsAPI?.createEntity('Player')
* .addComponent(Position, 100, 100)
* .addComponent(Velocity, 50, 0);
*
* // 查询实体
* const enemies = Core.ecsAPI?.query(Enemy, Transform);
*
* // 发射事件
* Core.ecsAPI?.emit('game:start', { level: 1 });
* ```
*/
public static get ecsAPI() {
if (!this._instance) {
return null;
}
return this._instance._sceneManager.api;
}
/**
* 延迟加载场景(下一帧切换)
*
* @param scene - 要加载的场景
*
* @example
* ```typescript
* // 延迟切换场景(在下一帧生效)
* Core.loadScene(new MenuScene());
* ```
*/
public static loadScene<T extends IScene>(scene: T): void {
if (!this._instance) {
Core._logger.warn("Core实例未创建请先调用Core.create()");
return;
}
this._instance._sceneManager.loadScene(scene);
}
/**
* 更新游戏逻辑
*
* 此方法应该在游戏引擎的更新循环中调用。
* 会自动更新全局服务和当前场景。
*
* @param deltaTime - 外部引擎提供的帧时间间隔(秒)
*
* @example
* ```typescript
* // Laya引擎
* // 初始化
* Core.create({ debug: true });
* Core.setScene(new GameScene());
*
* // Laya引擎集成
* Laya.timer.frameLoop(1, this, () => {
* const deltaTime = Laya.timer.delta / 1000;
* Core.update(deltaTime);
* Core.update(deltaTime); // 自动更新全局服务和场景
* });
*
* // Cocos Creator
* // Cocos Creator集成
* update(deltaTime: number) {
* Core.update(deltaTime);
* Core.update(deltaTime); // 自动更新全局服务和场景
* }
*
* ```
*/
public static update(deltaTime: number): void {
@@ -351,6 +378,19 @@ export class Core {
* @param context - 回调函数的上下文默认为null
* @param onTime - 定时器触发时的回调函数
* @returns 创建的定时器实例
*
* @example
* ```typescript
* // 一次性定时器
* Core.schedule(1.0, false, null, (timer) => {
* console.log("1秒后执行一次");
* });
*
* // 重复定时器
* Core.schedule(0.5, true, null, (timer) => {
* console.log("每0.5秒执行一次");
* });
* ```
*/
public static schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean = false, context?: TContext, onTime?: (timer: ITimer<TContext>) => void): Timer<TContext> {
if (!onTime) {
@@ -359,15 +399,6 @@ export class Core {
return this._instance._timerManager.schedule(timeInSeconds, repeats, context as TContext, onTime);
}
/**
* 获取ECS流式API
*
* @returns ECS API实例如果未初始化则返回null
*/
public static get ecsAPI(): ECSFluentAPI | null {
return this._instance?._ecsAPI || null;
}
/**
* 启用调试功能
*
@@ -428,98 +459,6 @@ export class Core {
return this._instance?._config.debugConfig?.enabled || false;
}
/**
* 获取WorldManager实例
*
* @param config 可选的WorldManager配置用于覆盖默认配置
* @returns WorldManager实例如果未初始化则自动创建
*/
public static getWorldManager(config?: Partial<IWorldManagerConfig>): WorldManager {
if (!this._instance) {
throw new Error("Core实例未创建请先调用Core.create()");
}
if (!this._instance._worldManager) {
// 多World模式的配置用户主动获取WorldManager
const defaultConfig = {
maxWorlds: 50,
autoCleanup: true,
cleanupInterval: 60000,
debug: this._instance._config.debug
};
this._instance._worldManager = WorldManager.getInstance({
...defaultConfig,
...config // 用户传入的配置会覆盖默认配置
});
}
return this._instance._worldManager;
}
/**
* 启用World管理
*
* 显式启用World功能用于多房间/多世界架构
*
* @param config 可选的WorldManager配置用于覆盖默认配置
*/
public static enableWorldManager(config?: Partial<IWorldManagerConfig>): WorldManager {
return this.getWorldManager(config);
}
/**
* 确保默认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);
}
}
/**
* 场景切换回调
*
* 在场景切换时调用,用于重置时间系统等。
*/
public onSceneChanged() {
Time.sceneChanged();
// 获取当前Scene从默认World
const currentScene = Core.getScene();
// 初始化ECS API如果场景支持
if (currentScene && currentScene.querySystem && currentScene.eventSystem) {
this._ecsAPI = createECSAPI(currentScene, currentScene.querySystem, currentScene.eventSystem);
}
// 延迟调试管理器通知,避免在场景初始化过程中干扰属性
if (this._debugManager) {
queueMicrotask(() => {
this._debugManager?.onSceneChanged();
});
}
}
/**
* 初始化核心系统
*
@@ -527,9 +466,13 @@ export class Core {
*/
protected initialize() {
// 核心系统初始化
Core._logger.info('Core initialized', {
debug: this.debug,
entitySystemsEnabled: Core.entitySystemsEnabled,
debugEnabled: this._config.debugConfig?.enabled || false
});
}
/**
* 内部更新方法
*
@@ -560,26 +503,8 @@ export class Core {
// 更新对象池管理器
this._poolManager.update();
// 更新所有World
if (this._worldManager) {
const worldsStartTime = this._performanceMonitor.startMonitoring('Worlds.update');
const activeWorlds = this._worldManager.getActiveWorlds();
let totalWorldEntities = 0;
for (const world of activeWorlds) {
// 更新World的全局System
world.updateGlobalSystems();
// 更新World中的所有Scene
world.updateScenes();
// 统计实体数量(用于性能监控)
const worldStats = world.getStats();
totalWorldEntities += worldStats.totalEntities;
}
this._performanceMonitor.endMonitoring('Worlds.update', worldsStartTime, totalWorldEntities);
}
// 更新场景
this._sceneManager.update();
// 更新调试管理器基于FPS的数据发送
if (this._debugManager) {
@@ -589,4 +514,29 @@ export class Core {
// 结束性能监控
this._performanceMonitor.endMonitoring('Core.update', frameStartTime);
}
/**
* 销毁Core实例
*
* 清理所有资源,通常在应用程序关闭时调用。
*/
public static destroy(): void {
if (!this._instance) return;
// 停止调试管理器
if (this._instance._debugManager) {
this._instance._debugManager.stop();
}
// 清理全局管理器
for (const manager of this._instance._globalManagers) {
manager.enabled = false;
}
this._instance._globalManagers = [];
Core._logger.info('Core destroyed');
// @ts-ignore - 清空实例引用
this._instance = null;
}
}

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

View File

@@ -31,39 +31,44 @@ export interface IWorldManagerConfig {
/**
* World管理器 - 管理所有World实例
*
* WorldManager是全局单例负责管理所有World的生命周期
* WorldManager负责管理多个独立的World实例
* 每个World都是独立的ECS环境可以包含多个Scene。
*
* 设计理念
* - Core负责单Scene的传统ECS管理
* - World负责多Scene的管理和协调
* - WorldManager负责多World的全局管理
* 适用场景
* - MMO游戏的多房间管理
* - 服务器端的多游戏实例
* - 需要完全隔离的多个游戏环境
*
* @example
* ```typescript
* // 获取全局WorldManager
* const worldManager = WorldManager.getInstance();
* // 创建WorldManager实例
* const worldManager = new WorldManager({
* maxWorlds: 100,
* autoCleanup: true
* });
*
* // 创建游戏房间World
* const roomWorld = worldManager.createWorld('room_001', {
* const room1 = worldManager.createWorld('room_001', {
* name: 'GameRoom_001',
* maxScenes: 5
* });
* room1.setActive(true);
*
* // 游戏循环中更新所有World
* worldManager.updateAll(deltaTime);
* // 游戏循环
* function gameLoop(deltaTime: number) {
* Core.update(deltaTime);
* worldManager.updateAll(); // 更新所有活跃World
* }
* ```
*/
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 _cleanupTimer: ReturnType<typeof setInterval> | null = null;
private _isRunning: boolean = false;
private constructor(config: IWorldManagerConfig = {}) {
public constructor(config: IWorldManagerConfig = {}) {
this._config = {
maxWorlds: 50,
autoCleanup: true,
@@ -72,6 +77,9 @@ export class WorldManager {
...config
};
// 默认启动运行状态
this._isRunning = true;
logger.info('WorldManager已初始化', {
maxWorlds: this._config.maxWorlds,
autoCleanup: this._config.autoCleanup,
@@ -81,26 +89,6 @@ export class WorldManager {
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管理 =====
/**
@@ -205,9 +193,37 @@ export class WorldManager {
// ===== 批量操作 =====
/**
* 更新所有活跃的World
*
* 应该在每帧的游戏循环中调用。
* 会自动更新所有活跃World的全局系统和场景。
*
* @example
* ```typescript
* function gameLoop(deltaTime: number) {
* Core.update(deltaTime); // 更新全局服务
* worldManager.updateAll(); // 更新所有World
* }
* ```
*/
public updateAll(): void {
if (!this._isRunning) return;
for (const worldId of this._activeWorlds) {
const world = this._worlds.get(worldId);
if (world && world.isActive) {
// 更新World的全局System
world.updateGlobalSystems();
// 更新World中的所有Scene
world.updateScenes();
}
}
}
/**
* 获取所有激活的World
* 注意此方法供Core.update()使用
*/
public getActiveWorlds(): World[] {
const activeWorlds: World[] = [];

View File

@@ -6,6 +6,7 @@ export * from './Utils';
export * from './Decorators';
export { Scene } from './Scene';
export { IScene, ISceneFactory, ISceneConfig } from './IScene';
export { SceneManager } from './SceneManager';
export { World, IWorldConfig } from './World';
export { WorldManager, IWorldManagerConfig } from './WorldManager';
export * from './Core/Events';

View File

@@ -9,7 +9,7 @@ export class WebSocketManager {
private reconnectInterval: number = 2000;
private url: string;
private autoReconnect: boolean;
private reconnectTimer?: NodeJS.Timeout;
private reconnectTimer?: ReturnType<typeof setTimeout>;
private onOpen?: (event: Event) => void;
private onClose?: (event: CloseEvent) => void;
private onError?: (error: Event | any) => void;

View File

@@ -1,10 +1,10 @@
import { Core } from '../src/Core';
import { Scene } from '../src/ECS/Scene';
import { SceneManager } from '../src/ECS/SceneManager';
import { Entity } from '../src/ECS/Entity';
import { Component } from '../src/ECS/Component';
import { GlobalManager } from '../src/Utils/GlobalManager';
import { ITimer } from '../src/Utils/Timers/ITimer';
import { WorldManager } from '../src/ECS/WorldManager';
// 测试组件
class TestComponent extends Component {
@@ -66,8 +66,7 @@ describe('Core - 核心管理系统测试', () => {
// 清除之前的实例
(Core as any)._instance = null;
// 重置WorldManager全局状态
WorldManager.reset();
// 注意:WorldManager不再是单例无需reset
// 模拟console.warn以避免测试输出
originalConsoleWarn = console.warn;
@@ -79,10 +78,9 @@ describe('Core - 核心管理系统测试', () => {
console.warn = originalConsoleWarn;
// 清理Core实例
(Core as any)._instance = null;
// 重置WorldManager全局状态
WorldManager.reset();
if (Core.Instance) {
Core.destroy();
}
});
describe('实例创建和管理', () => {
@@ -128,85 +126,27 @@ describe('Core - 核心管理系统测试', () => {
});
});
describe('场景管理', () => {
// 注意场景管理功能已移至SceneManager
// 相关测试请查看 SceneManager.test.ts
describe('更新循环 - 全局服务', () => {
let core: Core;
let testScene: TestScene;
beforeEach(() => {
core = Core.create(true);
testScene = new TestScene();
});
test('应该能够设置场景', () => {
Core.setScene(testScene);
expect(Core.scene).toBe(testScene);
expect(testScene.beginCalled).toBe(true);
});
test('应该能够使用推荐的setScene方法设置场景', () => {
const scene = Core.setScene(testScene);
expect(Core.scene).toBe(testScene);
expect(testScene.beginCalled).toBe(true);
expect(scene).toBe(testScene); // 应该返回场景实例
});
test('设置新场景应该触发场景切换', () => {
const firstScene = new TestScene();
const secondScene = new TestScene();
// 设置第一个场景
Core.setScene(firstScene);
expect(firstScene.beginCalled).toBe(true);
// 设置第二个场景(应该在下一帧切换)
Core.setScene(secondScene);
// 模拟更新循环触发场景切换
Core.update(0.016);
expect(firstScene.endCalled).toBe(true);
expect(secondScene.beginCalled).toBe(true);
expect(Core.scene).toBe(secondScene);
});
test('获取场景在未设置时应该返回null', () => {
// 创建全新的Core实例确保没有场景设置
const core = Core.create(false);
expect(Core.scene).toBeNull();
});
});
describe('更新循环', () => {
let core: Core;
let testScene: TestScene;
let globalManager: TestGlobalManager;
beforeEach(() => {
core = Core.create(true);
testScene = new TestScene();
globalManager = new TestGlobalManager();
Core.registerGlobalManager(globalManager);
Core.setScene(testScene);
});
test('应该能够执行更新循环', () => {
const deltaTime = 0.016;
Core.update(deltaTime);
expect(testScene.updateCallCount).toBe(1);
test('应该能够更新全局管理器', () => {
Core.update(0.016);
expect(globalManager.updateCallCount).toBe(1);
});
test('暂停状态下不应该执行更新', () => {
Core.paused = true;
Core.update(0.016);
expect(testScene.updateCallCount).toBe(0);
expect(globalManager.updateCallCount).toBe(0);
// 恢复状态
@@ -215,9 +155,7 @@ describe('Core - 核心管理系统测试', () => {
test('禁用的全局管理器不应该被更新', () => {
globalManager.enabled = false;
Core.update(0.016);
expect(globalManager.updateCallCount).toBe(0);
});
@@ -225,8 +163,6 @@ describe('Core - 核心管理系统测试', () => {
Core.update(0.016);
Core.update(0.016);
Core.update(0.016);
expect(testScene.updateCallCount).toBe(3);
expect(globalManager.updateCallCount).toBe(3);
});
});
@@ -410,41 +346,8 @@ describe('Core - 核心管理系统测试', () => {
});
});
describe('ECS API集成', () => {
let core: Core;
let testScene: TestScene;
beforeEach(() => {
core = Core.create(true);
testScene = new TestScene();
});
test('设置支持ECS的场景应该初始化ECS API', () => {
// 模拟带有querySystem和eventSystem的场景
const ecsScene = Object.assign(testScene, {
querySystem: { query: jest.fn() },
eventSystem: { emit: jest.fn() }
});
Core.setScene(ecsScene);
expect(Core.ecsAPI).toBeDefined();
});
test('设置普通场景不应该初始化ECS API', () => {
// 创建一个普通场景对象不继承Scene
const plainScene = {
initialize: () => {},
begin: () => {},
end: () => {},
update: () => {}
};
Core.setScene(plainScene as any);
expect(Core.ecsAPI).toBeNull();
});
});
// ECS API 现在由 SceneManager 管理
// 相关测试请查看 SceneManager.test.ts
describe('性能监控集成', () => {
let core: Core;
@@ -462,9 +365,6 @@ describe('Core - 核心管理系统测试', () => {
});
test('更新循环应该包含性能监控', () => {
const scene = new TestScene();
Core.setScene(scene);
const performanceMonitor = (core as any)._performanceMonitor;
const startMonitoringSpy = jest.spyOn(performanceMonitor, 'startMonitoring');
const endMonitoringSpy = jest.spyOn(performanceMonitor, 'endMonitoring');
@@ -475,32 +375,4 @@ describe('Core - 核心管理系统测试', () => {
expect(endMonitoringSpy).toHaveBeenCalled();
});
});
describe('错误处理', () => {
test('设置null场景应该被忽略', () => {
const core = Core.create(false);
// Core的新架构中场景不能直接设置为null
// 默认情况下Core.scene应该为null没有设置场景时
expect(Core.scene).toBeNull();
});
test('应该处理场景更新中的异常', () => {
const core = Core.create(true);
const errorScene = new TestScene();
// 模拟场景更新抛出异常
errorScene.update = () => {
throw new Error('Test error');
};
Core.setScene(errorScene);
// 由于Core目前不捕获场景异常我们预期它会抛出异常
// 这是一个已知的行为,可以在未来版本中改进
expect(() => {
Core.update(0.016);
}).toThrow('Test error');
});
});
});

View File

@@ -2,6 +2,7 @@ import { Core } from '../../../src/Core';
import { Scene } from '../../../src/ECS/Scene';
import { World, IGlobalSystem } from '../../../src/ECS/World';
import { WorldManager } from '../../../src/ECS/WorldManager';
import { SceneManager } from '../../../src/ECS/SceneManager';
import { EntitySystem } from '../../../src/ECS/Systems/EntitySystem';
import { Component } from '../../../src/ECS/Component';
import { Matcher } from '../../../src/ECS/Utils/Matcher';
@@ -21,71 +22,7 @@ class TestComponent extends Component {
}
}
class NetworkComponent extends Component {
public playerId: string;
constructor(playerId: string) {
super();
this.playerId = playerId;
}
public reset(): void {
this.playerId = '';
}
}
// 测试用系统
class TestGlobalSystem extends EntitySystem {
public processedEntities: Entity[] = [];
public updateCount: number = 0;
constructor() {
super(Matcher.empty().all(TestComponent));
}
protected override process(entities: Entity[]): void {
this.processedEntities = [...entities];
this.updateCount++;
}
}
// 正确的全局系统实现
class NetworkSyncGlobalSystem implements IGlobalSystem {
public readonly name = 'NetworkSyncSystem';
public updateCount: number = 0;
public initialize(): void {
// 初始化网络连接等
}
public update(): void {
this.updateCount++;
// 同步网络数据等全局逻辑
}
public reset(): void {
this.updateCount = 0;
}
public destroy(): void {
// 清理网络连接等
}
}
// Scene级别的EntitySystem正确的用法
class NetworkSyncSystem extends EntitySystem {
public syncCount: number = 0;
constructor() {
super(Matcher.empty().all(NetworkComponent));
}
protected override process(entities: Entity[]): void {
this.syncCount++;
}
}
// World级别的网络同步全局系统
// 全局系统实现
class NetworkGlobalSystem implements IGlobalSystem {
public readonly name = 'NetworkGlobalSystem';
public syncCount: number = 0;
@@ -108,482 +45,151 @@ class NetworkGlobalSystem implements IGlobalSystem {
}
}
// 测试用Scene
class TestScene extends Scene {
public updateCallCount: number = 0;
public override update(): void {
super.update();
this.updateCallCount++;
}
}
/**
* World与Core集成测试
*
* 注意v3.0重构后Core不再直接管理Scene/World
* - 场景管理由 SceneManager 负责
* - 多世界管理由 WorldManager 负责
* - Core 仅负责全局服务Timer、Performance等
*
* 大部分旧的集成测试已移至 SceneManager.test.ts 和 WorldManager.test.ts
*/
describe('World与Core集成测试', () => {
let worldManager: WorldManager;
let sceneManager: SceneManager;
beforeEach(() => {
// 重置Core和WorldManager
if ((Core as any)._instance) {
(Core as any)._instance = null;
// 重置Core
if (Core.Instance) {
Core.destroy();
}
WorldManager['_instance'] = null;
Core.create({ debug: false });
// WorldManager和SceneManager不再是单例
worldManager = new WorldManager();
sceneManager = new SceneManager();
});
afterEach(() => {
// 清理资源
if ((Core as any)._instance) {
const worldManager = Core.getWorldManager?.();
if (worldManager) {
const worldIds = worldManager.getWorldIds();
worldIds.forEach(id => {
worldManager.removeWorld(id);
});
}
(Core as any)._instance = null;
if (sceneManager) {
sceneManager.destroy();
}
if (worldManager) {
worldManager.destroy();
}
if (Core.Instance) {
Core.destroy();
}
WorldManager['_instance'] = null;
});
describe('融合设计基础功能', () => {
test('单Scene模式应该保持向后兼容', () => {
Core.create({ debug: false });
describe('基础功能', () => {
test('Core应该能够独立运行', () => {
expect(Core.Instance).toBeDefined();
// 传统单Scene用法
// Core.update 仅更新全局服务
Core.update(0.016);
});
test('SceneManager应该能够独立管理场景', () => {
const scene = new Scene();
scene.name = 'TestScene';
Core.setScene(scene);
sceneManager.setScene(scene);
const retrievedScene = Core.getScene();
expect(retrievedScene).toBe(scene);
expect(retrievedScene?.name).toBe('TestScene');
expect(sceneManager.currentScene).toBe(scene);
expect(sceneManager.hasScene).toBe(true);
// 场景更新独立于Core
sceneManager.update();
});
test('启用WorldManager应该支持多World功能', () => {
Core.create({ debug: false });
Core.enableWorldManager();
test('WorldManager应该能够独立管理多个World', () => {
const world1 = worldManager.createWorld('world1');
const world2 = worldManager.createWorld('world2');
const worldManager = Core.getWorldManager();
expect(worldManager).toBeDefined();
const world = worldManager.createWorld('TestWorld');
expect(world).toBeDefined();
expect(world.name).toBe('TestWorld');
});
test('getWorldManager应该自动创建WorldManager', () => {
Core.create({ debug: false });
// 获取WorldManager会自动创建实例
const worldManager = Core.getWorldManager();
expect(worldManager).toBeDefined();
// 多次获取应该返回同一个实例
const worldManager2 = Core.getWorldManager();
expect(worldManager2).toBe(worldManager);
});
test('单Scene模式下Core.update应该正常工作', () => {
Core.create({ debug: false });
const scene = new TestScene();
Core.setScene(scene);
// 模拟更新
Core.update(0.016);
expect(scene.updateCallCount).toBeGreaterThan(0);
expect(worldManager.worldCount).toBe(2);
expect(worldManager.getWorld('world1')).toBe(world1);
expect(worldManager.getWorld('world2')).toBe(world2);
});
});
describe('默认World机制', () => {
test('设置Scene应该自动创建默认World', () => {
Core.create({ debug: false });
describe('组合使用', () => {
test('Core + SceneManager 应该正确协作', () => {
const scene = new Scene();
Core.setScene(scene);
sceneManager.setScene(scene);
// 启用WorldManager后应该能看到默认World
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const entity = scene.createEntity('TestEntity');
entity.addComponent(new TestComponent(42));
expect(worldManager.getWorld('__default__')).toBeDefined();
// 游戏循环
Core.update(0.016); // 更新全局服务
sceneManager.update(); // 更新场景
const defaultWorld = worldManager.getWorld('__default__');
expect(defaultWorld).toBeDefined();
expect(defaultWorld?.getScene('__main__')).toBe(scene);
expect(scene.entities.count).toBe(1);
});
test('默认World的Scene应该正确激活', () => {
Core.create({ debug: false });
test('Core + WorldManager 应该正确协作', () => {
const world = worldManager.createWorld('test-world');
const scene = world.createScene('main', new Scene());
world.setActive(true);
const scene = new Scene();
Core.setScene(scene);
// 游戏循环
Core.update(0.016); // 更新全局服务
worldManager.updateAll(); // 更新所有World
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const defaultWorld = worldManager.getWorld('__default__');
expect(defaultWorld?.isSceneActive('__main__')).toBe(true);
expect(world.isActive).toBe(true);
});
test('替换默认Scene应该正确处理', () => {
Core.create({ debug: false });
test('World的全局系统应该能够正常工作', () => {
const world = worldManager.createWorld('test-world');
const globalSystem = new NetworkGlobalSystem();
world.addGlobalSystem(globalSystem);
world.setActive(true);
// 更新World
worldManager.updateAll();
expect(globalSystem.syncCount).toBeGreaterThan(0);
});
});
describe('隔离性测试', () => {
test('多个WorldManager实例应该完全隔离', () => {
const manager1 = new WorldManager();
const manager2 = new WorldManager();
manager1.createWorld('world1');
manager2.createWorld('world2');
expect(manager1.getWorld('world1')).toBeDefined();
expect(manager1.getWorld('world2')).toBeNull();
expect(manager2.getWorld('world2')).toBeDefined();
expect(manager2.getWorld('world1')).toBeNull();
// 清理
manager1.destroy();
manager2.destroy();
});
test('多个SceneManager实例应该完全隔离', () => {
const sm1 = new SceneManager();
const sm2 = new SceneManager();
const scene1 = new Scene();
scene1.name = 'Scene1';
Core.setScene(scene1);
const scene2 = new Scene();
scene2.name = 'Scene2';
Core.setScene(scene2);
const currentScene = Core.getScene();
expect(currentScene).toBe(scene2);
expect(currentScene?.name).toBe('Scene2');
});
});
sm1.setScene(scene1);
sm2.setScene(scene2);
describe('多World更新机制', () => {
test('Core.update应该更新所有活跃World', () => {
Core.create({ debug: false });
Core.enableWorldManager();
expect(sm1.currentScene).toBe(scene1);
expect(sm2.currentScene).toBe(scene2);
const worldManager = Core.getWorldManager();
// 创建多个World
const world1 = worldManager.createWorld('World1');
const world2 = worldManager.createWorld('World2');
const world3 = worldManager.createWorld('World3');
// 为每个World创建Scene和System
const scene1 = world1.createScene('scene1', new TestScene());
const scene2 = world2.createScene('scene2', new TestScene());
const scene3 = world3.createScene('scene3', new TestScene());
// 启动部分World
worldManager.setWorldActive('World1', true);
worldManager.setWorldActive('World2', true);
// world3保持未启动
world1.setSceneActive('scene1', true);
world2.setSceneActive('scene2', true);
// 执行更新
Core.update(0.016);
// 检查只有激活的World被更新
expect(scene1.updateCallCount).toBeGreaterThan(0);
expect(scene2.updateCallCount).toBeGreaterThan(0);
expect(scene3.updateCallCount).toBe(0);
});
test('全局系统应该在Scene更新前执行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const world = worldManager.createWorld('TestWorld');
// 添加正确设计的全局系统业务逻辑系统不是EntitySystem
const globalSystem = new NetworkSyncGlobalSystem();
world.addGlobalSystem(globalSystem);
// 创建Scene
const scene = world.createScene('testScene');
worldManager.setWorldActive('TestWorld', true);
world.setSceneActive('testScene', true);
// 执行更新
Core.update(0.016);
// 验证全局System被正确更新
expect(globalSystem.updateCount).toBeGreaterThan(0);
});
});
describe('多房间游戏服务器场景', () => {
test('多个游戏房间应该独立运行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建两个游戏房间
const room1 = worldManager.createWorld('Room_001');
const room2 = worldManager.createWorld('Room_002');
// 为每个房间设置Scene
const gameScene1 = room1.createScene('game');
const gameScene2 = room2.createScene('game');
// 为每个房间添加全局网络系统
const netSystem1 = new NetworkGlobalSystem();
const netSystem2 = new NetworkGlobalSystem();
room1.addGlobalSystem(netSystem1);
room2.addGlobalSystem(netSystem2);
// 在每个房间创建玩家
const player1 = gameScene1.createEntity('Player1');
player1.addComponent(new NetworkComponent('player_123'));
const player2 = gameScene2.createEntity('Player2');
player2.addComponent(new NetworkComponent('player_456'));
// 启动房间
worldManager.setWorldActive('Room_001', true);
worldManager.setWorldActive('Room_002', true);
room1.setSceneActive('game', true);
room2.setSceneActive('game', true);
// 模拟游戏循环
for (let i = 0; i < 5; i++) {
Core.update(0.016);
}
// 验证每个房间独立运行
expect(netSystem1.syncCount).toBeGreaterThan(0);
expect(netSystem2.syncCount).toBeGreaterThan(0);
expect(room1.getActiveSceneCount()).toBe(1);
expect(room2.getActiveSceneCount()).toBe(1);
});
test('房间销毁应该完全清理资源', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建房间
const room = worldManager.createWorld('TempRoom');
const scene = room.createScene('game');
// 添加内容
for (let i = 0; i < 10; i++) {
const entity = scene.createEntity(`Entity${i}`);
entity.addComponent(new TestComponent(i));
}
room.addGlobalSystem(new NetworkSyncGlobalSystem());
worldManager.setWorldActive('TempRoom', true);
room.setSceneActive('game', true);
// 验证房间正常运行
Core.update(0.016);
const beforeDestroy = worldManager.getStats();
expect(beforeDestroy.totalWorlds).toBe(1);
expect(beforeDestroy.activeWorlds).toBe(1);
// 销毁房间
worldManager.removeWorld('TempRoom');
const afterDestroy = worldManager.getStats();
expect(afterDestroy.totalWorlds).toBe(0);
expect(afterDestroy.activeWorlds).toBe(0);
});
});
describe('客户端多层Scene架构', () => {
test('分层Scene应该同时运行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const clientWorld = worldManager.createWorld('ClientWorld');
// 创建不同层的Scene
const gameplayScene = clientWorld.createScene('gameplay', new TestScene());
const uiScene = clientWorld.createScene('ui', new TestScene());
const effectsScene = clientWorld.createScene('effects', new TestScene());
// 启动世界并激活所有Scene
worldManager.setWorldActive('ClientWorld', true);
clientWorld.setSceneActive('gameplay', true);
clientWorld.setSceneActive('ui', true);
clientWorld.setSceneActive('effects', true);
// 执行更新
Core.update(0.016);
// 验证所有Scene都被更新
expect(gameplayScene.updateCallCount).toBeGreaterThan(0);
expect(uiScene.updateCallCount).toBeGreaterThan(0);
expect(effectsScene.updateCallCount).toBeGreaterThan(0);
});
test('Scene的动态激活和停用', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const world = worldManager.createWorld('DynamicWorld');
const gameScene = world.createScene('game', new TestScene());
const menuScene = world.createScene('menu', new TestScene());
worldManager.setWorldActive('DynamicWorld', true);
// 初始状态只有游戏Scene激活
world.setSceneActive('game', true);
world.setSceneActive('menu', false);
Core.update(0.016);
const gameCount1 = gameScene.updateCallCount;
const menuCount1 = menuScene.updateCallCount;
// 切换到菜单
world.setSceneActive('game', false);
world.setSceneActive('menu', true);
Core.update(0.016);
const gameCount2 = gameScene.updateCallCount;
const menuCount2 = menuScene.updateCallCount;
// 验证Scene状态切换
expect(gameCount2).toBe(gameCount1); // 游戏Scene停止更新
expect(menuCount2).toBeGreaterThan(menuCount1); // 菜单Scene开始更新
});
});
describe('性能和稳定性', () => {
test('大量World和Scene应该稳定运行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const worldCount = 20;
const scenePerWorld = 3;
// 创建大量World和Scene
for (let i = 0; i < worldCount; i++) {
const world = worldManager.createWorld(`World${i}`);
for (let j = 0; j < scenePerWorld; j++) {
const scene = world.createScene(`Scene${j}`, new TestScene());
// 添加一些实体
for (let k = 0; k < 5; k++) {
const entity = scene.createEntity(`Entity${k}`);
entity.addComponent(new TestComponent(k));
}
world.setSceneActive(`Scene${j}`, true);
}
worldManager.setWorldActive(`World${i}`, true);
}
// 验证所有资源创建成功
expect(worldManager.getWorldIds()).toHaveLength(worldCount);
expect(worldManager.getActiveWorlds()).toHaveLength(worldCount);
// 执行多次更新测试稳定性
for (let i = 0; i < 10; i++) {
expect(() => {
Core.update(0.016);
}).not.toThrow();
}
// 验证更新正常工作
const activeWorlds = worldManager.getActiveWorlds();
activeWorlds.forEach(world => {
const scenes = world.getAllScenes();
scenes.forEach(scene => {
if (scene instanceof TestScene && world.isSceneActive(scene.name)) {
expect(scene.updateCallCount).toBeGreaterThan(0);
}
});
});
});
test('频繁的World创建和销毁应该不影响性能', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 频繁创建和销毁World
for (let cycle = 0; cycle < 10; cycle++) {
// 创建批次World
const worldIds: string[] = [];
for (let i = 0; i < 5; i++) {
const worldId = `Cycle${cycle}_World${i}`;
worldIds.push(worldId);
const world = worldManager.createWorld(worldId);
const scene = world.createScene('test');
scene.createEntity('entity');
worldManager.setWorldActive(worldId, true);
world.setSceneActive('test', true);
}
// 更新一次
Core.update(0.016);
// 销毁批次World
worldIds.forEach(id => {
worldManager.removeWorld(id);
});
// 验证清理完成
expect(worldManager.getWorldIds()).toHaveLength(0);
expect(worldManager.getActiveWorlds()).toHaveLength(0);
}
});
});
describe('错误处理和边界情况', () => {
test('Core未初始化时操作应该抛出合适错误', () => {
// getScene 会返回 null 而不是抛出错误
expect(Core.getScene()).toBeNull();
expect(() => {
Core.setScene(new Scene());
}).toThrow();
});
test('在World销毁后继续操作应该安全', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const world = worldManager.createWorld('DestroyTest');
worldManager.setWorldActive('DestroyTest', true);
worldManager.removeWorld('DestroyTest');
// 对已销毁的World进行操作应该不会崩溃
expect(() => {
world.updateGlobalSystems();
world.updateScenes();
}).not.toThrow();
});
test('混合使用单Scene和多World模式', () => {
Core.create({ debug: false });
// 直接启用WorldManager避免先使用单Scene创建限制性配置
const worldManager = Core.getWorldManager();
// 然后使用单Scene模式
const singleScene = new Scene();
Core.setScene(singleScene);
// 验证默认World被创建
expect(worldManager.getWorld('__default__')).toBeDefined();
// 创建额外的World
const extraWorld = worldManager.createWorld('ExtraWorld');
worldManager.setWorldActive('ExtraWorld', true);
// 两种模式应该能共存
expect(() => {
Core.update(0.016);
}).not.toThrow();
// 清理
sm1.destroy();
sm2.destroy();
});
});
});

View File

@@ -41,9 +41,8 @@ describe('WorldManager', () => {
let worldManager: WorldManager;
beforeEach(() => {
// 重置单
WorldManager['_instance'] = null;
worldManager = WorldManager.getInstance();
// WorldManager不再是单例直接创建新实
worldManager = new WorldManager();
});
afterEach(() => {
@@ -56,30 +55,37 @@ describe('WorldManager', () => {
// 清理定时器
worldManager.destroy();
}
WorldManager['_instance'] = null;
});
describe('单例模式', () => {
test('获取实例应该返回相同的实例', () => {
const instance1 = WorldManager.getInstance();
const instance2 = WorldManager.getInstance();
describe('实例化', () => {
test('可以创建多个独立的WorldManager实例', () => {
const manager1 = new WorldManager();
const manager2 = new WorldManager();
expect(instance1).toBe(instance2);
expect(manager1).not.toBe(manager2);
manager1.createWorld('world1');
expect(manager2.getWorld('world1')).toBeNull();
// 清理
manager1.destroy();
manager2.destroy();
});
test('使用配置创建实例应该正确', () => {
WorldManager['_instance'] = null;
const config: IWorldManagerConfig = {
maxWorlds: 10,
autoCleanup: true,
debug: false
};
const instance = WorldManager.getInstance(config);
const instance = new WorldManager(config);
expect(instance).toBeDefined();
expect(instance).toBe(WorldManager.getInstance());
expect(instance.worldCount).toBe(0);
// 清理
instance.destroy();
});
});
@@ -115,8 +121,7 @@ describe('WorldManager', () => {
});
test('超出最大World数量应该抛出错误', () => {
WorldManager['_instance'] = null;
const limitedManager = WorldManager.getInstance({ maxWorlds: 2 });
const limitedManager = new WorldManager({ maxWorlds: 2 });
limitedManager.createWorld('world1');
limitedManager.createWorld('world2');
@@ -126,8 +131,7 @@ describe('WorldManager', () => {
}).toThrow("已达到最大World数量限制: 2");
// 清理
limitedManager.removeWorld('world1');
limitedManager.removeWorld('world2');
limitedManager.destroy();
});
test('获取World应该正确', () => {
@@ -430,20 +434,18 @@ describe('WorldManager', () => {
};
expect(() => {
WorldManager.getInstance(invalidConfig);
new WorldManager(invalidConfig);
}).not.toThrow();
});
test('配置更新应该影响后续操作', () => {
WorldManager['_instance'] = null;
test('配置应该正确应用于新实例', () => {
const config: IWorldManagerConfig = {
maxWorlds: 3,
autoCleanup: true,
debug: true
};
const manager = WorldManager.getInstance(config);
const manager = new WorldManager(config);
// 创建到限制数量的World
manager.createWorld('world1');
@@ -456,9 +458,7 @@ describe('WorldManager', () => {
}).toThrow();
// 清理
manager.removeWorld('world1');
manager.removeWorld('world2');
manager.removeWorld('world3');
manager.destroy();
});
});
});