2025-10-11 11:33:07 +08:00
|
|
|
|
# WorldManager
|
|
|
|
|
|
|
|
|
|
|
|
WorldManager 是 ECS Framework 提供的高级世界管理器,用于管理多个完全隔离的游戏世界(World)。每个 World 都是独立的 ECS 环境,可以包含多个场景。
|
|
|
|
|
|
|
|
|
|
|
|
## 适用场景
|
|
|
|
|
|
|
|
|
|
|
|
WorldManager 适合以下高级场景:
|
|
|
|
|
|
- MMO 游戏服务器的多房间管理
|
|
|
|
|
|
- 游戏大厅系统(每个游戏房间完全隔离)
|
|
|
|
|
|
- 服务器端的多游戏实例
|
|
|
|
|
|
- 需要完全隔离的多个游戏环境
|
|
|
|
|
|
- 需要同时运行多个独立世界的应用
|
|
|
|
|
|
|
|
|
|
|
|
## 特点
|
|
|
|
|
|
|
|
|
|
|
|
- 多 World 管理,每个 World 完全独立
|
|
|
|
|
|
- 每个 World 可以包含多个 Scene
|
|
|
|
|
|
- 支持 World 的激活/停用
|
|
|
|
|
|
- 自动清理空 World
|
|
|
|
|
|
- World 级别的全局系统
|
|
|
|
|
|
- 批量操作和查询
|
|
|
|
|
|
|
|
|
|
|
|
## 基本使用
|
|
|
|
|
|
|
|
|
|
|
|
### 初始化
|
|
|
|
|
|
|
|
|
|
|
|
WorldManager 是 Core 的内置服务,通过服务容器获取:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
2025-12-08 21:26:35 +08:00
|
|
|
|
import { Core, WorldManager } from '@esengine/ecs-framework';
|
2025-10-11 11:33:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化 Core
|
|
|
|
|
|
Core.create({ debug: true });
|
|
|
|
|
|
|
|
|
|
|
|
// 从服务容器获取 WorldManager(Core 已自动创建并注册)
|
|
|
|
|
|
const worldManager = Core.services.resolve(WorldManager);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 创建 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 创建游戏房间 World
|
|
|
|
|
|
const room1 = worldManager.createWorld('room_001', {
|
|
|
|
|
|
name: 'GameRoom_001',
|
|
|
|
|
|
maxScenes: 5,
|
|
|
|
|
|
debug: true
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 激活 World
|
|
|
|
|
|
worldManager.setWorldActive('room_001', true);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建更多房间
|
|
|
|
|
|
const room2 = worldManager.createWorld('room_002', {
|
|
|
|
|
|
name: 'GameRoom_002',
|
|
|
|
|
|
maxScenes: 5
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
worldManager.setWorldActive('room_002', true);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 游戏循环
|
|
|
|
|
|
|
|
|
|
|
|
在游戏循环中更新所有活跃的 World:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
function gameLoop(deltaTime: number) {
|
|
|
|
|
|
Core.update(deltaTime); // 更新全局服务
|
|
|
|
|
|
worldManager.updateAll(); // 更新所有活跃的 World
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 启动游戏循环
|
|
|
|
|
|
let lastTime = 0;
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
|
|
const currentTime = Date.now();
|
|
|
|
|
|
const deltaTime = (currentTime - lastTime) / 1000;
|
|
|
|
|
|
lastTime = currentTime;
|
|
|
|
|
|
|
|
|
|
|
|
gameLoop(deltaTime);
|
|
|
|
|
|
}, 16); // 60 FPS
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## World 管理
|
|
|
|
|
|
|
|
|
|
|
|
### 创建 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 基本创建
|
|
|
|
|
|
const world = worldManager.createWorld('worldId');
|
|
|
|
|
|
|
|
|
|
|
|
// 带配置创建
|
|
|
|
|
|
const world = worldManager.createWorld('worldId', {
|
|
|
|
|
|
name: 'MyWorld',
|
|
|
|
|
|
maxScenes: 10,
|
|
|
|
|
|
autoCleanup: true,
|
|
|
|
|
|
debug: true
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**配置选项(IWorldConfig)**:
|
|
|
|
|
|
- `name?: string` - World 名称
|
|
|
|
|
|
- `maxScenes?: number` - 最大场景数量限制(默认 10)
|
|
|
|
|
|
- `autoCleanup?: boolean` - 是否自动清理空场景(默认 true)
|
|
|
|
|
|
- `debug?: boolean` - 是否启用调试模式(默认 false)
|
|
|
|
|
|
|
|
|
|
|
|
### 获取 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 通过 ID 获取
|
|
|
|
|
|
const world = worldManager.getWorld('room_001');
|
|
|
|
|
|
if (world) {
|
|
|
|
|
|
console.log(`World: ${world.name}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有 World
|
|
|
|
|
|
const allWorlds = worldManager.getAllWorlds();
|
|
|
|
|
|
console.log(`共有 ${allWorlds.length} 个 World`);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有 World ID
|
|
|
|
|
|
const worldIds = worldManager.getWorldIds();
|
|
|
|
|
|
console.log('World 列表:', worldIds);
|
|
|
|
|
|
|
|
|
|
|
|
// 通过名称查找
|
|
|
|
|
|
const world = worldManager.findWorldByName('GameRoom_001');
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 激活和停用 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 激活 World(开始运行和更新)
|
|
|
|
|
|
worldManager.setWorldActive('room_001', true);
|
|
|
|
|
|
|
|
|
|
|
|
// 停用 World(停止更新但保留数据)
|
|
|
|
|
|
worldManager.setWorldActive('room_001', false);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查 World 是否激活
|
|
|
|
|
|
if (worldManager.isWorldActive('room_001')) {
|
|
|
|
|
|
console.log('房间正在运行');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有活跃的 World
|
|
|
|
|
|
const activeWorlds = worldManager.getActiveWorlds();
|
|
|
|
|
|
console.log(`当前有 ${activeWorlds.length} 个活跃 World`);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 移除 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 移除 World(会自动停用并销毁)
|
|
|
|
|
|
const removed = worldManager.removeWorld('room_001');
|
|
|
|
|
|
if (removed) {
|
|
|
|
|
|
console.log('World 已移除');
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## World 中的场景管理
|
|
|
|
|
|
|
|
|
|
|
|
每个 World 可以包含多个 Scene 并独立管理它们的生命周期。
|
|
|
|
|
|
|
|
|
|
|
|
### 创建场景
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const world = worldManager.getWorld('room_001');
|
|
|
|
|
|
if (!world) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建场景
|
|
|
|
|
|
const mainScene = world.createScene('main', new MainScene());
|
|
|
|
|
|
const uiScene = world.createScene('ui', new UIScene());
|
|
|
|
|
|
const hudScene = world.createScene('hud', new HUDScene());
|
|
|
|
|
|
|
|
|
|
|
|
// 激活场景
|
|
|
|
|
|
world.setSceneActive('main', true);
|
|
|
|
|
|
world.setSceneActive('ui', true);
|
|
|
|
|
|
world.setSceneActive('hud', false);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 查询场景
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 获取特定场景
|
|
|
|
|
|
const mainScene = world.getScene<MainScene>('main');
|
|
|
|
|
|
if (mainScene) {
|
|
|
|
|
|
console.log(`场景名称: ${mainScene.name}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有场景
|
|
|
|
|
|
const allScenes = world.getAllScenes();
|
|
|
|
|
|
console.log(`World 中共有 ${allScenes.length} 个场景`);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有场景 ID
|
|
|
|
|
|
const sceneIds = world.getSceneIds();
|
|
|
|
|
|
console.log('场景列表:', sceneIds);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取活跃场景数量
|
|
|
|
|
|
const activeCount = world.getActiveSceneCount();
|
|
|
|
|
|
console.log(`当前有 ${activeCount} 个活跃场景`);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查场景是否激活
|
|
|
|
|
|
if (world.isSceneActive('main')) {
|
|
|
|
|
|
console.log('主场景正在运行');
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 场景切换
|
|
|
|
|
|
|
|
|
|
|
|
World 支持多场景同时运行,也支持场景切换:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
class GameWorld {
|
|
|
|
|
|
private world: World;
|
|
|
|
|
|
|
|
|
|
|
|
constructor(worldManager: WorldManager) {
|
|
|
|
|
|
this.world = worldManager.createWorld('game', {
|
|
|
|
|
|
name: 'GameWorld',
|
|
|
|
|
|
maxScenes: 5
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 创建所有场景
|
|
|
|
|
|
this.world.createScene('menu', new MenuScene());
|
|
|
|
|
|
this.world.createScene('game', new GameScene());
|
|
|
|
|
|
this.world.createScene('pause', new PauseScene());
|
|
|
|
|
|
this.world.createScene('gameover', new GameOverScene());
|
|
|
|
|
|
|
|
|
|
|
|
// 激活 World
|
|
|
|
|
|
worldManager.setWorldActive('game', true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public showMenu(): void {
|
|
|
|
|
|
this.deactivateAllScenes();
|
|
|
|
|
|
this.world.setSceneActive('menu', true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public startGame(): void {
|
|
|
|
|
|
this.deactivateAllScenes();
|
|
|
|
|
|
this.world.setSceneActive('game', true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public pauseGame(): void {
|
|
|
|
|
|
// 游戏场景继续存在但停止更新
|
|
|
|
|
|
this.world.setSceneActive('game', false);
|
|
|
|
|
|
// 显示暂停界面
|
|
|
|
|
|
this.world.setSceneActive('pause', true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public resumeGame(): void {
|
|
|
|
|
|
this.world.setSceneActive('pause', false);
|
|
|
|
|
|
this.world.setSceneActive('game', true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public showGameOver(): void {
|
|
|
|
|
|
this.deactivateAllScenes();
|
|
|
|
|
|
this.world.setSceneActive('gameover', true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private deactivateAllScenes(): void {
|
|
|
|
|
|
const sceneIds = this.world.getSceneIds();
|
|
|
|
|
|
sceneIds.forEach(id => this.world.setSceneActive(id, false));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 移除场景
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 移除不再需要的场景
|
|
|
|
|
|
const removed = world.removeScene('oldScene');
|
|
|
|
|
|
if (removed) {
|
|
|
|
|
|
console.log('场景已移除');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 场景会自动调用 end() 方法进行清理
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 全局系统
|
|
|
|
|
|
|
|
|
|
|
|
World 支持全局系统,这些系统在 World 级别运行,不依赖特定 Scene。
|
|
|
|
|
|
|
|
|
|
|
|
### 定义全局系统
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
2025-12-08 21:26:35 +08:00
|
|
|
|
import { IGlobalSystem } from '@esengine/ecs-framework';
|
2025-10-11 11:33:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 网络系统(World 级别)
|
|
|
|
|
|
class NetworkSystem implements IGlobalSystem {
|
|
|
|
|
|
readonly name = 'NetworkSystem';
|
|
|
|
|
|
|
|
|
|
|
|
private connectionId: string;
|
|
|
|
|
|
|
|
|
|
|
|
constructor(connectionId: string) {
|
|
|
|
|
|
this.connectionId = connectionId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
initialize(): void {
|
|
|
|
|
|
console.log(`网络系统初始化: ${this.connectionId}`);
|
|
|
|
|
|
// 建立网络连接
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
update(deltaTime?: number): void {
|
|
|
|
|
|
// 处理网络消息,不依赖任何 Scene
|
|
|
|
|
|
// 接收和发送网络包
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
destroy(): void {
|
|
|
|
|
|
console.log(`网络系统销毁: ${this.connectionId}`);
|
|
|
|
|
|
// 关闭网络连接
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 物理系统(World 级别)
|
|
|
|
|
|
class PhysicsSystem implements IGlobalSystem {
|
|
|
|
|
|
readonly name = 'PhysicsSystem';
|
|
|
|
|
|
|
|
|
|
|
|
initialize(): void {
|
|
|
|
|
|
console.log('物理系统初始化');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
update(deltaTime?: number): void {
|
|
|
|
|
|
// 物理模拟,作用于 World 中所有场景
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
destroy(): void {
|
|
|
|
|
|
console.log('物理系统销毁');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 使用全局系统
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const world = worldManager.getWorld('room_001');
|
|
|
|
|
|
if (!world) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加全局系统
|
|
|
|
|
|
const networkSystem = world.addGlobalSystem(new NetworkSystem('conn_001'));
|
|
|
|
|
|
const physicsSystem = world.addGlobalSystem(new PhysicsSystem());
|
|
|
|
|
|
|
|
|
|
|
|
// 获取全局系统
|
|
|
|
|
|
const network = world.getGlobalSystem(NetworkSystem);
|
|
|
|
|
|
if (network) {
|
|
|
|
|
|
console.log('找到网络系统');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 移除全局系统
|
|
|
|
|
|
world.removeGlobalSystem(networkSystem);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 批量操作
|
|
|
|
|
|
|
|
|
|
|
|
### 更新所有 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 更新所有活跃的 World(应该在游戏循环中调用)
|
|
|
|
|
|
worldManager.updateAll();
|
|
|
|
|
|
|
|
|
|
|
|
// 这会自动更新每个 World 的:
|
|
|
|
|
|
// 1. 全局系统
|
|
|
|
|
|
// 2. 所有活跃场景
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 启动和停止
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 启动所有 World
|
|
|
|
|
|
worldManager.startAll();
|
|
|
|
|
|
|
|
|
|
|
|
// 停止所有 World
|
|
|
|
|
|
worldManager.stopAll();
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否正在运行
|
|
|
|
|
|
if (worldManager.isRunning) {
|
|
|
|
|
|
console.log('WorldManager 正在运行');
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 查找 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 使用条件查找
|
|
|
|
|
|
const emptyWorlds = worldManager.findWorlds(world => {
|
|
|
|
|
|
return world.sceneCount === 0;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 查找活跃的 World
|
|
|
|
|
|
const activeWorlds = worldManager.findWorlds(world => {
|
|
|
|
|
|
return world.isActive;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 查找特定名称的 World
|
|
|
|
|
|
const world = worldManager.findWorldByName('GameRoom_001');
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 统计和监控
|
|
|
|
|
|
|
|
|
|
|
|
### 获取统计信息
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const stats = worldManager.getStats();
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`总 World 数: ${stats.totalWorlds}`);
|
|
|
|
|
|
console.log(`活跃 World 数: ${stats.activeWorlds}`);
|
|
|
|
|
|
console.log(`总场景数: ${stats.totalScenes}`);
|
|
|
|
|
|
console.log(`总实体数: ${stats.totalEntities}`);
|
|
|
|
|
|
console.log(`总系统数: ${stats.totalSystems}`);
|
|
|
|
|
|
|
|
|
|
|
|
// 查看每个 World 的详细信息
|
|
|
|
|
|
stats.worlds.forEach(worldInfo => {
|
|
|
|
|
|
console.log(`World: ${worldInfo.name}`);
|
|
|
|
|
|
console.log(` 场景数: ${worldInfo.sceneCount}`);
|
|
|
|
|
|
console.log(` 是否活跃: ${worldInfo.isActive}`);
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 获取详细状态
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const status = worldManager.getDetailedStatus();
|
|
|
|
|
|
|
|
|
|
|
|
// 包含所有 World 的详细状态
|
|
|
|
|
|
status.worlds.forEach(worldStatus => {
|
|
|
|
|
|
console.log(`World ID: ${worldStatus.id}`);
|
|
|
|
|
|
console.log(`状态:`, worldStatus.status);
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 自动清理
|
|
|
|
|
|
|
|
|
|
|
|
WorldManager 支持自动清理空的 World。
|
|
|
|
|
|
|
|
|
|
|
|
### 配置清理
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 创建带清理配置的 WorldManager
|
|
|
|
|
|
const worldManager = Core.services.resolve(WorldManager);
|
|
|
|
|
|
|
|
|
|
|
|
// WorldManager 的配置在 Core 中设置:
|
|
|
|
|
|
// {
|
|
|
|
|
|
// maxWorlds: 50,
|
|
|
|
|
|
// autoCleanup: true,
|
2025-11-09 17:35:07 +08:00
|
|
|
|
// cleanupFrameInterval: 1800 // 间隔多少帧清理闲置 World
|
2025-10-11 11:33:07 +08:00
|
|
|
|
// }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 手动清理
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 手动触发清理
|
|
|
|
|
|
const cleanedCount = worldManager.cleanup();
|
|
|
|
|
|
console.log(`清理了 ${cleanedCount} 个 World`);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**清理条件**:
|
|
|
|
|
|
- World 未激活
|
|
|
|
|
|
- 没有 Scene 或所有 Scene 都是空的
|
|
|
|
|
|
- 创建时间超过 10 分钟
|
|
|
|
|
|
|
|
|
|
|
|
## API 参考
|
|
|
|
|
|
|
|
|
|
|
|
### WorldManager API
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `createWorld(worldId, config?)` | 创建新 World |
|
|
|
|
|
|
| `removeWorld(worldId)` | 移除 World |
|
|
|
|
|
|
| `getWorld(worldId)` | 获取 World |
|
|
|
|
|
|
| `getAllWorlds()` | 获取所有 World |
|
|
|
|
|
|
| `getWorldIds()` | 获取所有 World ID |
|
|
|
|
|
|
| `setWorldActive(worldId, active)` | 设置 World 激活状态 |
|
|
|
|
|
|
| `isWorldActive(worldId)` | 检查 World 是否激活 |
|
|
|
|
|
|
| `getActiveWorlds()` | 获取所有活跃的 World |
|
|
|
|
|
|
| `updateAll()` | 更新所有活跃 World |
|
|
|
|
|
|
| `startAll()` | 启动所有 World |
|
|
|
|
|
|
| `stopAll()` | 停止所有 World |
|
|
|
|
|
|
| `findWorlds(predicate)` | 查找满足条件的 World |
|
|
|
|
|
|
| `findWorldByName(name)` | 根据名称查找 World |
|
|
|
|
|
|
| `getStats()` | 获取统计信息 |
|
|
|
|
|
|
| `getDetailedStatus()` | 获取详细状态信息 |
|
|
|
|
|
|
| `cleanup()` | 清理空 World |
|
|
|
|
|
|
| `destroy()` | 销毁 WorldManager |
|
|
|
|
|
|
|
|
|
|
|
|
### World API
|
|
|
|
|
|
|
|
|
|
|
|
| 方法 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `createScene(sceneId, sceneInstance?)` | 创建并添加 Scene |
|
|
|
|
|
|
| `removeScene(sceneId)` | 移除 Scene |
|
|
|
|
|
|
| `getScene(sceneId)` | 获取 Scene |
|
|
|
|
|
|
| `getAllScenes()` | 获取所有 Scene |
|
|
|
|
|
|
| `getSceneIds()` | 获取所有 Scene ID |
|
|
|
|
|
|
| `setSceneActive(sceneId, active)` | 设置 Scene 激活状态 |
|
|
|
|
|
|
| `isSceneActive(sceneId)` | 检查 Scene 是否激活 |
|
|
|
|
|
|
| `getActiveSceneCount()` | 获取活跃 Scene 数量 |
|
|
|
|
|
|
| `addGlobalSystem(system)` | 添加全局系统 |
|
|
|
|
|
|
| `removeGlobalSystem(system)` | 移除全局系统 |
|
|
|
|
|
|
| `getGlobalSystem(type)` | 获取全局系统 |
|
|
|
|
|
|
| `start()` | 启动 World |
|
|
|
|
|
|
| `stop()` | 停止 World |
|
|
|
|
|
|
| `updateGlobalSystems()` | 更新全局系统 |
|
|
|
|
|
|
| `updateScenes()` | 更新所有激活 Scene |
|
|
|
|
|
|
| `destroy()` | 销毁 World |
|
|
|
|
|
|
| `getStatus()` | 获取 World 状态 |
|
|
|
|
|
|
| `getStats()` | 获取统计信息 |
|
|
|
|
|
|
|
|
|
|
|
|
### 属性
|
|
|
|
|
|
|
|
|
|
|
|
| 属性 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `worldCount` | World 总数 |
|
|
|
|
|
|
| `activeWorldCount` | 活跃 World 数量 |
|
|
|
|
|
|
| `isRunning` | 是否正在运行 |
|
|
|
|
|
|
| `config` | 配置信息 |
|
|
|
|
|
|
|
|
|
|
|
|
## 完整示例
|
|
|
|
|
|
|
|
|
|
|
|
### MMO 游戏房间系统
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
2025-12-08 21:26:35 +08:00
|
|
|
|
import { Core, WorldManager, Scene, World } from '@esengine/ecs-framework';
|
2025-10-11 11:33:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
|
Core.create({ debug: true });
|
|
|
|
|
|
const worldManager = Core.services.resolve(WorldManager);
|
|
|
|
|
|
|
|
|
|
|
|
// 房间管理器
|
|
|
|
|
|
class RoomManager {
|
|
|
|
|
|
private worldManager: WorldManager;
|
|
|
|
|
|
private rooms: Map<string, World> = new Map();
|
|
|
|
|
|
|
|
|
|
|
|
constructor(worldManager: WorldManager) {
|
|
|
|
|
|
this.worldManager = worldManager;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建游戏房间
|
|
|
|
|
|
public createRoom(roomId: string, maxPlayers: number): World {
|
|
|
|
|
|
const world = this.worldManager.createWorld(roomId, {
|
|
|
|
|
|
name: `Room_${roomId}`,
|
|
|
|
|
|
maxScenes: 3,
|
|
|
|
|
|
debug: true
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 创建房间场景
|
|
|
|
|
|
world.createScene('lobby', new LobbyScene());
|
|
|
|
|
|
world.createScene('game', new GameScene());
|
|
|
|
|
|
world.createScene('result', new ResultScene());
|
|
|
|
|
|
|
|
|
|
|
|
// 添加房间级别的系统
|
|
|
|
|
|
world.addGlobalSystem(new NetworkSystem(roomId));
|
|
|
|
|
|
world.addGlobalSystem(new RoomLogicSystem(maxPlayers));
|
|
|
|
|
|
|
|
|
|
|
|
// 激活 World 和初始场景
|
|
|
|
|
|
this.worldManager.setWorldActive(roomId, true);
|
|
|
|
|
|
world.setSceneActive('lobby', true);
|
|
|
|
|
|
|
|
|
|
|
|
this.rooms.set(roomId, world);
|
|
|
|
|
|
console.log(`房间 ${roomId} 已创建`);
|
|
|
|
|
|
|
|
|
|
|
|
return world;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 玩家加入房间
|
|
|
|
|
|
public joinRoom(roomId: string, playerId: string): boolean {
|
|
|
|
|
|
const world = this.rooms.get(roomId);
|
|
|
|
|
|
if (!world) {
|
|
|
|
|
|
console.log(`房间 ${roomId} 不存在`);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 在大厅场景中创建玩家实体
|
|
|
|
|
|
const lobbyScene = world.getScene('lobby');
|
|
|
|
|
|
if (lobbyScene) {
|
|
|
|
|
|
const player = lobbyScene.createEntity(`Player_${playerId}`);
|
|
|
|
|
|
// 添加玩家组件...
|
|
|
|
|
|
console.log(`玩家 ${playerId} 加入房间 ${roomId}`);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 开始游戏
|
|
|
|
|
|
public startGame(roomId: string): void {
|
|
|
|
|
|
const world = this.rooms.get(roomId);
|
|
|
|
|
|
if (!world) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到游戏场景
|
|
|
|
|
|
world.setSceneActive('lobby', false);
|
|
|
|
|
|
world.setSceneActive('game', true);
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`房间 ${roomId} 游戏开始`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 结束游戏
|
|
|
|
|
|
public endGame(roomId: string): void {
|
|
|
|
|
|
const world = this.rooms.get(roomId);
|
|
|
|
|
|
if (!world) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 切换到结果场景
|
|
|
|
|
|
world.setSceneActive('game', false);
|
|
|
|
|
|
world.setSceneActive('result', true);
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`房间 ${roomId} 游戏结束`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭房间
|
|
|
|
|
|
public closeRoom(roomId: string): void {
|
|
|
|
|
|
this.worldManager.removeWorld(roomId);
|
|
|
|
|
|
this.rooms.delete(roomId);
|
|
|
|
|
|
console.log(`房间 ${roomId} 已关闭`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取房间列表
|
|
|
|
|
|
public getRoomList(): string[] {
|
|
|
|
|
|
return Array.from(this.rooms.keys());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取房间统计
|
|
|
|
|
|
public getRoomStats(roomId: string) {
|
|
|
|
|
|
const world = this.rooms.get(roomId);
|
|
|
|
|
|
return world?.getStats();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用房间管理器
|
|
|
|
|
|
const roomManager = new RoomManager(worldManager);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建多个游戏房间
|
|
|
|
|
|
roomManager.createRoom('room_001', 4);
|
|
|
|
|
|
roomManager.createRoom('room_002', 4);
|
|
|
|
|
|
roomManager.createRoom('room_003', 2);
|
|
|
|
|
|
|
|
|
|
|
|
// 玩家加入
|
|
|
|
|
|
roomManager.joinRoom('room_001', 'player_1');
|
|
|
|
|
|
roomManager.joinRoom('room_001', 'player_2');
|
|
|
|
|
|
|
|
|
|
|
|
// 开始游戏
|
|
|
|
|
|
roomManager.startGame('room_001');
|
|
|
|
|
|
|
|
|
|
|
|
// 游戏循环
|
|
|
|
|
|
function gameLoop(deltaTime: number) {
|
|
|
|
|
|
Core.update(deltaTime);
|
|
|
|
|
|
worldManager.updateAll(); // 更新所有房间
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 定期清理空房间
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
|
|
const stats = worldManager.getStats();
|
|
|
|
|
|
console.log(`当前房间数: ${stats.totalWorlds}`);
|
|
|
|
|
|
console.log(`活跃房间数: ${stats.activeWorlds}`);
|
|
|
|
|
|
|
|
|
|
|
|
worldManager.cleanup();
|
|
|
|
|
|
}, 60000); // 每分钟清理一次
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 最佳实践
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 合理的 World 粒度
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 推荐:每个独立环境一个 World
|
|
|
|
|
|
const room1 = worldManager.createWorld('room_1'); // 游戏房间1
|
|
|
|
|
|
const room2 = worldManager.createWorld('room_2'); // 游戏房间2
|
|
|
|
|
|
|
|
|
|
|
|
// 不推荐:过度使用 World
|
|
|
|
|
|
const world1 = worldManager.createWorld('ui'); // UI 不需要独立 World
|
|
|
|
|
|
const world2 = worldManager.createWorld('menu'); // 菜单不需要独立 World
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 使用全局系统处理跨场景逻辑
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 推荐:World 级别的系统
|
|
|
|
|
|
class NetworkSystem implements IGlobalSystem {
|
|
|
|
|
|
update() {
|
|
|
|
|
|
// 网络处理不依赖场景
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不推荐:在每个场景中重复创建
|
|
|
|
|
|
class GameScene extends Scene {
|
|
|
|
|
|
initialize() {
|
|
|
|
|
|
this.addSystem(new NetworkSystem()); // 不应该在场景级别
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 及时清理不用的 World
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 推荐:玩家离开时清理房间
|
|
|
|
|
|
function onPlayerLeave(roomId: string) {
|
|
|
|
|
|
const world = worldManager.getWorld(roomId);
|
|
|
|
|
|
if (world && world.sceneCount === 0) {
|
|
|
|
|
|
worldManager.removeWorld(roomId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 或使用自动清理
|
|
|
|
|
|
worldManager.cleanup();
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 监控资源使用
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 定期检查资源使用情况
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
|
|
const stats = worldManager.getStats();
|
|
|
|
|
|
|
|
|
|
|
|
if (stats.totalWorlds > 100) {
|
|
|
|
|
|
console.warn('World 数量过多,考虑清理');
|
|
|
|
|
|
worldManager.cleanup();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (stats.totalEntities > 10000) {
|
|
|
|
|
|
console.warn('实体数量过多,检查是否有泄漏');
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 30000);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 与 SceneManager 的对比
|
|
|
|
|
|
|
|
|
|
|
|
| 特性 | SceneManager | WorldManager |
|
|
|
|
|
|
|------|--------------|--------------|
|
|
|
|
|
|
| 适用场景 | 95% 的游戏应用 | 高级多世界隔离场景 |
|
|
|
|
|
|
| 复杂度 | 简单 | 复杂 |
|
|
|
|
|
|
| 场景数量 | 单场景(可切换) | 多 World,每个 World 多场景 |
|
|
|
|
|
|
| 场景隔离 | 无(场景切换) | 完全隔离(每个 World 独立) |
|
|
|
|
|
|
| 性能开销 | 最小 | 较高 |
|
|
|
|
|
|
| 全局系统 | 无 | 支持(World 级别) |
|
|
|
|
|
|
| 使用示例 | 单人游戏、移动游戏 | MMO 服务器、游戏房间系统 |
|
|
|
|
|
|
|
|
|
|
|
|
**何时使用 WorldManager**:
|
|
|
|
|
|
- MMO 游戏服务器(每个房间一个 World)
|
|
|
|
|
|
- 游戏大厅系统(每个游戏房间完全隔离)
|
|
|
|
|
|
- 需要运行多个完全独立的游戏实例
|
|
|
|
|
|
- 服务器端模拟多个游戏世界
|
|
|
|
|
|
|
|
|
|
|
|
**何时使用 SceneManager**:
|
|
|
|
|
|
- 单人游戏
|
|
|
|
|
|
- 简单的多人游戏
|
|
|
|
|
|
- 移动游戏
|
|
|
|
|
|
- 场景之间需要切换但不需要同时运行
|
|
|
|
|
|
|
|
|
|
|
|
## 架构层次
|
|
|
|
|
|
|
|
|
|
|
|
WorldManager 在 ECS Framework 中的位置:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Core (全局服务)
|
|
|
|
|
|
└── WorldManager (世界管理)
|
|
|
|
|
|
├── World 1 (游戏房间1)
|
|
|
|
|
|
│ ├── GlobalSystem (全局系统)
|
|
|
|
|
|
│ ├── Scene 1 (场景1)
|
|
|
|
|
|
│ │ ├── EntitySystem
|
|
|
|
|
|
│ │ ├── Entity
|
|
|
|
|
|
│ │ └── Component
|
|
|
|
|
|
│ └── Scene 2 (场景2)
|
|
|
|
|
|
├── World 2 (游戏房间2)
|
|
|
|
|
|
│ ├── GlobalSystem
|
|
|
|
|
|
│ └── Scene 1
|
|
|
|
|
|
└── World 3 (游戏房间3)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
WorldManager 为需要多世界隔离的高级应用提供了强大的管理能力。如果你的应用不需要多世界隔离,建议使用更简单的 [SceneManager](./scene-manager.md)。
|