更新v2.2.1文档
This commit is contained in:
@@ -73,7 +73,14 @@ export default defineConfig({
|
|||||||
{ text: 'Worker系统 (多线程)', link: '/guide/worker-system' }
|
{ text: 'Worker系统 (多线程)', link: '/guide/worker-system' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ text: '场景管理 (Scene)', link: '/guide/scene' },
|
{
|
||||||
|
text: '场景管理 (Scene)',
|
||||||
|
link: '/guide/scene',
|
||||||
|
items: [
|
||||||
|
{ text: 'SceneManager', link: '/guide/scene-manager' },
|
||||||
|
{ text: 'WorldManager', link: '/guide/world-manager' }
|
||||||
|
]
|
||||||
|
},
|
||||||
{ text: '序列化系统 (Serialization)', link: '/guide/serialization' },
|
{ text: '序列化系统 (Serialization)', link: '/guide/serialization' },
|
||||||
{ text: '事件系统 (Event)', link: '/guide/event-system' },
|
{ text: '事件系统 (Event)', link: '/guide/event-system' },
|
||||||
{ text: '时间和定时器 (Time)', link: '/guide/time-and-timers' },
|
{ text: '时间和定时器 (Time)', link: '/guide/time-and-timers' },
|
||||||
|
|||||||
675
docs/guide/scene-manager.md
Normal file
675
docs/guide/scene-manager.md
Normal file
@@ -0,0 +1,675 @@
|
|||||||
|
# SceneManager
|
||||||
|
|
||||||
|
SceneManager 是 ECS Framework 提供的轻量级场景管理器,适用于 95% 的游戏应用。它提供简单直观的 API,支持场景切换和延迟加载。
|
||||||
|
|
||||||
|
## 适用场景
|
||||||
|
|
||||||
|
SceneManager 适合以下场景:
|
||||||
|
- 单人游戏
|
||||||
|
- 简单多人游戏
|
||||||
|
- 移动游戏
|
||||||
|
- 需要场景切换的游戏(菜单、游戏、暂停等)
|
||||||
|
- 不需要多 World 隔离的项目
|
||||||
|
|
||||||
|
## 特点
|
||||||
|
|
||||||
|
- 轻量级,零额外开销
|
||||||
|
- 简单直观的 API
|
||||||
|
- 支持延迟场景切换(避免在当前帧中途切换)
|
||||||
|
- 自动管理 ECS 流式 API
|
||||||
|
- 自动处理场景生命周期
|
||||||
|
- 集成在 Core 中,自动更新
|
||||||
|
|
||||||
|
## 基本使用
|
||||||
|
|
||||||
|
### 推荐方式:使用 Core 的静态方法
|
||||||
|
|
||||||
|
这是最简单和推荐的方式,适合大多数应用:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Core, Scene } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 1. 初始化 Core
|
||||||
|
Core.create({ debug: true });
|
||||||
|
|
||||||
|
// 2. 创建并设置场景
|
||||||
|
class GameScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "GameScene";
|
||||||
|
|
||||||
|
// 添加系统
|
||||||
|
this.addSystem(new MovementSystem());
|
||||||
|
this.addSystem(new RenderSystem());
|
||||||
|
|
||||||
|
// 创建初始实体
|
||||||
|
const player = this.createEntity("Player");
|
||||||
|
player.addComponent(new Transform(400, 300));
|
||||||
|
player.addComponent(new Health(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log("游戏场景已启动");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 设置场景
|
||||||
|
Core.setScene(new GameScene());
|
||||||
|
|
||||||
|
// 4. 游戏循环(Core.update 会自动更新场景)
|
||||||
|
function gameLoop(deltaTime: number) {
|
||||||
|
Core.update(deltaTime); // 自动更新所有服务和场景
|
||||||
|
}
|
||||||
|
|
||||||
|
// Laya 引擎集成
|
||||||
|
Laya.timer.frameLoop(1, this, () => {
|
||||||
|
const deltaTime = Laya.timer.delta / 1000;
|
||||||
|
Core.update(deltaTime);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cocos Creator 集成
|
||||||
|
update(deltaTime: number) {
|
||||||
|
Core.update(deltaTime);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 高级方式:直接使用 SceneManager
|
||||||
|
|
||||||
|
如果需要更多控制,可以直接使用 SceneManager:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Core, SceneManager, Scene } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 初始化 Core
|
||||||
|
Core.create({ debug: true });
|
||||||
|
|
||||||
|
// 获取 SceneManager(Core 已自动创建并注册)
|
||||||
|
const sceneManager = Core.services.resolve(SceneManager);
|
||||||
|
|
||||||
|
// 设置场景
|
||||||
|
const gameScene = new GameScene();
|
||||||
|
sceneManager.setScene(gameScene);
|
||||||
|
|
||||||
|
// 游戏循环(仍然使用 Core.update)
|
||||||
|
function gameLoop(deltaTime: number) {
|
||||||
|
Core.update(deltaTime); // Core会自动调用sceneManager.update()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**重要**:无论使用哪种方式,游戏循环中都应该只调用 `Core.update()`,它会自动更新 SceneManager 和场景。不需要手动调用 `sceneManager.update()`。
|
||||||
|
|
||||||
|
## 场景切换
|
||||||
|
|
||||||
|
### 立即切换
|
||||||
|
|
||||||
|
使用 `Core.setScene()` 或 `sceneManager.setScene()` 立即切换场景:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 方式1:使用 Core(推荐)
|
||||||
|
Core.setScene(new MenuScene());
|
||||||
|
|
||||||
|
// 方式2:使用 SceneManager
|
||||||
|
const sceneManager = Core.services.resolve(SceneManager);
|
||||||
|
sceneManager.setScene(new MenuScene());
|
||||||
|
```
|
||||||
|
|
||||||
|
### 延迟切换
|
||||||
|
|
||||||
|
使用 `Core.loadScene()` 或 `sceneManager.loadScene()` 延迟切换场景,场景会在下一帧切换:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 方式1:使用 Core(推荐)
|
||||||
|
Core.loadScene(new GameOverScene());
|
||||||
|
|
||||||
|
// 方式2:使用 SceneManager
|
||||||
|
const sceneManager = Core.services.resolve(SceneManager);
|
||||||
|
sceneManager.loadScene(new GameOverScene());
|
||||||
|
```
|
||||||
|
|
||||||
|
在 System 中切换场景时,应该使用延迟切换:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class GameOverSystem extends EntitySystem {
|
||||||
|
process(entities: readonly Entity[]): void {
|
||||||
|
const player = entities.find(e => e.name === 'Player');
|
||||||
|
const health = player?.getComponent(Health);
|
||||||
|
|
||||||
|
if (health && health.value <= 0) {
|
||||||
|
// 延迟切换到游戏结束场景(下一帧生效)
|
||||||
|
Core.loadScene(new GameOverScene());
|
||||||
|
// 当前帧继续执行,不会中断当前系统的处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 完整的场景切换示例
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Core, Scene } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
Core.create({ debug: true });
|
||||||
|
|
||||||
|
// 菜单场景
|
||||||
|
class MenuScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "MenuScene";
|
||||||
|
|
||||||
|
// 监听开始游戏事件
|
||||||
|
this.eventSystem.on('start_game', () => {
|
||||||
|
Core.loadScene(new GameScene());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log("显示菜单界面");
|
||||||
|
}
|
||||||
|
|
||||||
|
public unload(): void {
|
||||||
|
console.log("菜单场景卸载");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 游戏场景
|
||||||
|
class GameScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "GameScene";
|
||||||
|
|
||||||
|
// 创建游戏实体
|
||||||
|
const player = this.createEntity("Player");
|
||||||
|
player.addComponent(new Transform(400, 300));
|
||||||
|
player.addComponent(new Health(100));
|
||||||
|
|
||||||
|
// 监听游戏结束事件
|
||||||
|
this.eventSystem.on('game_over', () => {
|
||||||
|
Core.loadScene(new GameOverScene());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log("游戏开始");
|
||||||
|
}
|
||||||
|
|
||||||
|
public unload(): void {
|
||||||
|
console.log("游戏场景卸载");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 游戏结束场景
|
||||||
|
class GameOverScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "GameOverScene";
|
||||||
|
|
||||||
|
// 监听返回菜单事件
|
||||||
|
this.eventSystem.on('back_to_menu', () => {
|
||||||
|
Core.loadScene(new MenuScene());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log("显示游戏结束界面");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始游戏
|
||||||
|
Core.setScene(new MenuScene());
|
||||||
|
|
||||||
|
// 游戏循环
|
||||||
|
function gameLoop(deltaTime: number) {
|
||||||
|
Core.update(deltaTime); // 自动更新场景
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 参考
|
||||||
|
|
||||||
|
### Core 静态方法(推荐)
|
||||||
|
|
||||||
|
#### Core.setScene()
|
||||||
|
|
||||||
|
立即切换场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public static setScene<T extends IScene>(scene: T): T
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**:
|
||||||
|
- `scene` - 要设置的场景实例
|
||||||
|
|
||||||
|
**返回**:
|
||||||
|
- 返回设置的场景实例
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
```typescript
|
||||||
|
const gameScene = Core.setScene(new GameScene());
|
||||||
|
console.log(gameScene.name);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Core.loadScene()
|
||||||
|
|
||||||
|
延迟加载场景(下一帧切换)。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public static loadScene<T extends IScene>(scene: T): void
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**:
|
||||||
|
- `scene` - 要加载的场景实例
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
```typescript
|
||||||
|
Core.loadScene(new GameOverScene());
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Core.scene
|
||||||
|
|
||||||
|
获取当前活跃的场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public static get scene(): IScene | null
|
||||||
|
```
|
||||||
|
|
||||||
|
**返回**:
|
||||||
|
- 当前场景实例,如果没有场景则返回 null
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
```typescript
|
||||||
|
const currentScene = Core.scene;
|
||||||
|
if (currentScene) {
|
||||||
|
console.log(`当前场景: ${currentScene.name}`);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Core.ecsAPI
|
||||||
|
|
||||||
|
获取 ECS 流式 API。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public static get ecsAPI(): ECSFluentAPI | null
|
||||||
|
```
|
||||||
|
|
||||||
|
**返回**:
|
||||||
|
- ECS API 实例,如果当前没有场景则返回 null
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
```typescript
|
||||||
|
const api = Core.ecsAPI;
|
||||||
|
if (api) {
|
||||||
|
// 查询实体
|
||||||
|
const enemies = api.find(Enemy, Transform);
|
||||||
|
|
||||||
|
// 发射事件
|
||||||
|
api.emit('game:start', { level: 1 });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### SceneManager 方法(高级)
|
||||||
|
|
||||||
|
如果需要直接使用 SceneManager,可以通过服务容器获取:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const sceneManager = Core.services.resolve(SceneManager);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### setScene()
|
||||||
|
|
||||||
|
立即切换场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public setScene<T extends IScene>(scene: T): T
|
||||||
|
```
|
||||||
|
|
||||||
|
#### loadScene()
|
||||||
|
|
||||||
|
延迟加载场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public loadScene<T extends IScene>(scene: T): void
|
||||||
|
```
|
||||||
|
|
||||||
|
#### currentScene
|
||||||
|
|
||||||
|
获取当前场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public get currentScene(): IScene | null
|
||||||
|
```
|
||||||
|
|
||||||
|
#### api
|
||||||
|
|
||||||
|
获取 ECS 流式 API。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public get api(): ECSFluentAPI | null
|
||||||
|
```
|
||||||
|
|
||||||
|
#### hasScene
|
||||||
|
|
||||||
|
检查是否有活跃场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public get hasScene(): boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
#### hasPendingScene
|
||||||
|
|
||||||
|
检查是否有待切换的场景。
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
public get hasPendingScene(): boolean
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用 ECS 流式 API
|
||||||
|
|
||||||
|
通过 `Core.ecsAPI` 可以方便地访问场景的 ECS 功能:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const api = Core.ecsAPI;
|
||||||
|
if (!api) {
|
||||||
|
console.error('没有活跃场景');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询实体
|
||||||
|
const players = api.find(Player, Transform);
|
||||||
|
const enemies = api.find(Enemy, Health, Transform);
|
||||||
|
|
||||||
|
// 发射事件
|
||||||
|
api.emit('player:scored', { points: 100 });
|
||||||
|
|
||||||
|
// 监听事件
|
||||||
|
api.on('enemy:died', (data) => {
|
||||||
|
console.log('敌人死亡:', data);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 使用 Core 的静态方法
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 推荐:使用 Core 的静态方法
|
||||||
|
Core.setScene(new GameScene());
|
||||||
|
Core.loadScene(new MenuScene());
|
||||||
|
const currentScene = Core.scene;
|
||||||
|
|
||||||
|
// 不推荐:除非有特殊需求,否则不需要直接使用 SceneManager
|
||||||
|
const sceneManager = Core.services.resolve(SceneManager);
|
||||||
|
sceneManager.setScene(new GameScene());
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 只调用 Core.update()
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 正确:只调用 Core.update()
|
||||||
|
function gameLoop(deltaTime: number) {
|
||||||
|
Core.update(deltaTime); // 自动更新所有服务和场景
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误:不要手动调用 sceneManager.update()
|
||||||
|
function gameLoop(deltaTime: number) {
|
||||||
|
Core.update(deltaTime);
|
||||||
|
sceneManager.update(); // 重复更新,会导致问题!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 使用延迟切换避免问题
|
||||||
|
|
||||||
|
在 System 中切换场景时,应该使用 `loadScene()` 而不是 `setScene()`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 推荐:延迟切换
|
||||||
|
class HealthSystem extends EntitySystem {
|
||||||
|
process(entities: readonly Entity[]): void {
|
||||||
|
for (const entity of entities) {
|
||||||
|
const health = entity.getComponent(Health);
|
||||||
|
if (health.value <= 0) {
|
||||||
|
Core.loadScene(new GameOverScene());
|
||||||
|
// 当前帧继续处理其他实体
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不推荐:立即切换可能导致问题
|
||||||
|
class HealthSystem extends EntitySystem {
|
||||||
|
process(entities: readonly Entity[]): void {
|
||||||
|
for (const entity of entities) {
|
||||||
|
const health = entity.getComponent(Health);
|
||||||
|
if (health.value <= 0) {
|
||||||
|
Core.setScene(new GameOverScene());
|
||||||
|
// 场景立即切换,当前帧的其他实体可能无法正常处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 场景职责分离
|
||||||
|
|
||||||
|
每个场景应该只负责一个特定的游戏状态:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 好的设计 - 职责清晰
|
||||||
|
class MenuScene extends Scene {
|
||||||
|
// 只处理菜单相关逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameScene extends Scene {
|
||||||
|
// 只处理游戏玩法逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
class PauseScene extends Scene {
|
||||||
|
// 只处理暂停界面逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
// 避免的设计 - 职责混乱
|
||||||
|
class MegaScene extends Scene {
|
||||||
|
// 包含菜单、游戏、暂停等所有逻辑
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 资源管理
|
||||||
|
|
||||||
|
在场景的 `unload()` 方法中清理资源:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class GameScene extends Scene {
|
||||||
|
private textures: Map<string, any> = new Map();
|
||||||
|
private sounds: Map<string, any> = new Map();
|
||||||
|
|
||||||
|
protected initialize(): void {
|
||||||
|
this.loadResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadResources(): void {
|
||||||
|
this.textures.set('player', loadTexture('player.png'));
|
||||||
|
this.sounds.set('bgm', loadSound('bgm.mp3'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public unload(): void {
|
||||||
|
// 清理资源
|
||||||
|
this.textures.clear();
|
||||||
|
this.sounds.clear();
|
||||||
|
console.log('场景资源已清理');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 事件驱动的场景切换
|
||||||
|
|
||||||
|
使用事件系统来触发场景切换,保持代码解耦:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class GameScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
// 监听场景切换事件
|
||||||
|
this.eventSystem.on('goto:menu', () => {
|
||||||
|
Core.loadScene(new MenuScene());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventSystem.on('goto:gameover', (data) => {
|
||||||
|
Core.loadScene(new GameOverScene());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在 System 中触发事件
|
||||||
|
class GameLogicSystem extends EntitySystem {
|
||||||
|
process(entities: readonly Entity[]): void {
|
||||||
|
if (levelComplete) {
|
||||||
|
this.scene.eventSystem.emitSync('goto:gameover', {
|
||||||
|
score: 1000,
|
||||||
|
level: 5
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 架构层次
|
||||||
|
|
||||||
|
SceneManager 在 ECS Framework 中的位置:
|
||||||
|
|
||||||
|
```
|
||||||
|
Core (全局服务)
|
||||||
|
└── SceneManager (场景管理,自动更新)
|
||||||
|
└── Scene (当前场景)
|
||||||
|
├── EntitySystem (系统)
|
||||||
|
├── Entity (实体)
|
||||||
|
└── Component (组件)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与 WorldManager 的对比
|
||||||
|
|
||||||
|
| 特性 | SceneManager | WorldManager |
|
||||||
|
|------|--------------|--------------|
|
||||||
|
| 适用场景 | 95% 的游戏应用 | 高级多世界隔离场景 |
|
||||||
|
| 复杂度 | 简单 | 复杂 |
|
||||||
|
| 场景数量 | 单场景(可切换) | 多 World,每个 World 多场景 |
|
||||||
|
| 性能开销 | 最小 | 较高 |
|
||||||
|
| 使用方式 | `Core.setScene()` | `worldManager.createWorld()` |
|
||||||
|
|
||||||
|
**何时使用 SceneManager**:
|
||||||
|
- 单人游戏
|
||||||
|
- 简单的多人游戏
|
||||||
|
- 移动游戏
|
||||||
|
- 场景之间需要切换但不需要同时运行
|
||||||
|
|
||||||
|
**何时使用 WorldManager**:
|
||||||
|
- MMO 游戏服务器(每个房间一个 World)
|
||||||
|
- 游戏大厅系统(每个游戏房间完全隔离)
|
||||||
|
- 需要运行多个完全独立的游戏实例
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Core, Scene, EntitySystem, Entity, Matcher } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
class Transform {
|
||||||
|
constructor(public x: number, public y: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Velocity {
|
||||||
|
constructor(public vx: number, public vy: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Health {
|
||||||
|
constructor(public value: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义系统
|
||||||
|
class MovementSystem extends EntitySystem {
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.all(Transform, Velocity));
|
||||||
|
}
|
||||||
|
|
||||||
|
process(entities: readonly Entity[]): void {
|
||||||
|
for (const entity of entities) {
|
||||||
|
const transform = entity.getComponent(Transform);
|
||||||
|
const velocity = entity.getComponent(Velocity);
|
||||||
|
|
||||||
|
if (transform && velocity) {
|
||||||
|
transform.x += velocity.vx;
|
||||||
|
transform.y += velocity.vy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义场景
|
||||||
|
class MenuScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "MenuScene";
|
||||||
|
console.log("菜单场景初始化");
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log("菜单场景启动");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "GameScene";
|
||||||
|
|
||||||
|
// 添加系统
|
||||||
|
this.addSystem(new MovementSystem());
|
||||||
|
|
||||||
|
// 创建玩家
|
||||||
|
const player = this.createEntity("Player");
|
||||||
|
player.addComponent(new Transform(400, 300));
|
||||||
|
player.addComponent(new Velocity(0, 0));
|
||||||
|
player.addComponent(new Health(100));
|
||||||
|
|
||||||
|
// 创建敌人
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const enemy = this.createEntity(`Enemy_${i}`);
|
||||||
|
enemy.addComponent(new Transform(
|
||||||
|
Math.random() * 800,
|
||||||
|
Math.random() * 600
|
||||||
|
));
|
||||||
|
enemy.addComponent(new Velocity(
|
||||||
|
Math.random() * 100 - 50,
|
||||||
|
Math.random() * 100 - 50
|
||||||
|
));
|
||||||
|
enemy.addComponent(new Health(50));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log('游戏场景启动');
|
||||||
|
}
|
||||||
|
|
||||||
|
public unload(): void {
|
||||||
|
console.log('游戏场景卸载');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
Core.create({ debug: true });
|
||||||
|
|
||||||
|
// 设置初始场景
|
||||||
|
Core.setScene(new MenuScene());
|
||||||
|
|
||||||
|
// 游戏循环
|
||||||
|
let lastTime = 0;
|
||||||
|
function gameLoop(currentTime: number) {
|
||||||
|
const deltaTime = (currentTime - lastTime) / 1000;
|
||||||
|
lastTime = currentTime;
|
||||||
|
|
||||||
|
// 只需要调用 Core.update,它会自动更新场景
|
||||||
|
Core.update(deltaTime);
|
||||||
|
|
||||||
|
requestAnimationFrame(gameLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(gameLoop);
|
||||||
|
|
||||||
|
// 切换到游戏场景
|
||||||
|
setTimeout(() => {
|
||||||
|
Core.loadScene(new GameScene());
|
||||||
|
}, 3000);
|
||||||
|
```
|
||||||
|
|
||||||
|
SceneManager 为大多数游戏提供了简单而强大的场景管理能力。通过 Core 的静态方法,你可以轻松地管理场景切换。如果你需要更高级的多世界隔离功能,请参考 [WorldManager](./world-manager.md) 文档。
|
||||||
@@ -11,6 +11,22 @@
|
|||||||
- 事件系统支持
|
- 事件系统支持
|
||||||
- 性能监控和调试信息
|
- 性能监控和调试信息
|
||||||
|
|
||||||
|
## 场景管理方式
|
||||||
|
|
||||||
|
ECS Framework 提供了两种场景管理方式:
|
||||||
|
|
||||||
|
1. **[SceneManager](./scene-manager.md)** - 适用于 95% 的游戏应用
|
||||||
|
- 单人游戏、简单多人游戏、移动游戏
|
||||||
|
- 轻量级,简单直观的 API
|
||||||
|
- 支持场景切换
|
||||||
|
|
||||||
|
2. **[WorldManager](./world-manager.md)** - 适用于高级多世界隔离场景
|
||||||
|
- MMO 游戏服务器、游戏房间系统
|
||||||
|
- 多 World 管理,每个 World 可包含多个场景
|
||||||
|
- 完全隔离的独立环境
|
||||||
|
|
||||||
|
本文档重点介绍 Scene 类本身的使用方法。关于场景管理器的详细信息,请查看对应的文档。
|
||||||
|
|
||||||
## 创建场景
|
## 创建场景
|
||||||
|
|
||||||
### 继承 Scene 类
|
### 继承 Scene 类
|
||||||
@@ -106,6 +122,13 @@ const scene = new ExampleScene();
|
|||||||
// 场景的 initialize(), begin(), update(), end() 由框架自动调用
|
// 场景的 initialize(), begin(), update(), end() 由框架自动调用
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**生命周期方法**:
|
||||||
|
|
||||||
|
1. `initialize()` - 场景初始化,设置系统和初始实体
|
||||||
|
2. `begin()` / `onStart()` - 场景开始运行
|
||||||
|
3. `update()` - 每帧更新(由场景管理器调用)
|
||||||
|
4. `end()` / `unload()` - 场景卸载,清理资源
|
||||||
|
|
||||||
## 实体管理
|
## 实体管理
|
||||||
|
|
||||||
### 创建实体
|
### 创建实体
|
||||||
@@ -247,15 +270,42 @@ class EventScene extends Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public triggerGameEvent(): void {
|
public triggerGameEvent(): void {
|
||||||
// 发送事件
|
// 发送事件(同步)
|
||||||
this.eventSystem.emitSync('custom_event', {
|
this.eventSystem.emitSync('custom_event', {
|
||||||
message: "这是自定义事件",
|
message: "这是自定义事件",
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 发送事件(异步)
|
||||||
|
this.eventSystem.emit('async_event', {
|
||||||
|
data: "异步事件数据"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 事件系统 API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 监听事件
|
||||||
|
this.eventSystem.on('event_name', callback);
|
||||||
|
|
||||||
|
// 监听一次(自动取消订阅)
|
||||||
|
this.eventSystem.once('event_name', callback);
|
||||||
|
|
||||||
|
// 取消监听
|
||||||
|
this.eventSystem.off('event_name', callback);
|
||||||
|
|
||||||
|
// 同步发送事件
|
||||||
|
this.eventSystem.emitSync('event_name', data);
|
||||||
|
|
||||||
|
// 异步发送事件
|
||||||
|
this.eventSystem.emit('event_name', data);
|
||||||
|
|
||||||
|
// 清除所有事件监听
|
||||||
|
this.eventSystem.clear();
|
||||||
|
```
|
||||||
|
|
||||||
## 场景统计和调试
|
## 场景统计和调试
|
||||||
|
|
||||||
### 获取场景统计
|
### 获取场景统计
|
||||||
@@ -287,176 +337,58 @@ class StatsScene extends Scene {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 场景集成到框架
|
## 组件查询
|
||||||
|
|
||||||
ECS Framework 提供了灵活的场景管理架构,适用于不同规模的应用:
|
Scene 提供了强大的组件查询系统:
|
||||||
|
|
||||||
### 1. 使用 SceneManager(推荐大多数应用)
|
|
||||||
|
|
||||||
适用于 95% 的游戏应用(单人游戏、简单多人游戏、移动游戏等):
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Core, Scene, SceneManager } from '@esengine/ecs-framework';
|
class QueryScene extends Scene {
|
||||||
|
|
||||||
// 初始化Core(全局服务)
|
|
||||||
Core.create({ debug: true });
|
|
||||||
|
|
||||||
// 从服务容器获取 SceneManager(Core 已自动创建并注册)
|
|
||||||
const sceneManager = Core.services.resolve(SceneManager);
|
|
||||||
|
|
||||||
// 创建游戏场景
|
|
||||||
class GameScene extends Scene {
|
|
||||||
protected initialize(): void {
|
protected initialize(): void {
|
||||||
this.name = "GameScene";
|
// 创建一些实体
|
||||||
this.addSystem(new MovementSystem());
|
for (let i = 0; i < 10; i++) {
|
||||||
this.addSystem(new RenderSystem());
|
const entity = this.createEntity(`Entity_${i}`);
|
||||||
}
|
entity.addComponent(new Transform(i * 10, 0));
|
||||||
}
|
entity.addComponent(new Velocity(1, 0));
|
||||||
|
if (i % 2 === 0) {
|
||||||
// 设置场景
|
entity.addComponent(new Renderer());
|
||||||
const gameScene = new GameScene();
|
}
|
||||||
sceneManager.setScene(gameScene);
|
}
|
||||||
|
|
||||||
// 游戏循环
|
|
||||||
function gameLoop(deltaTime: number) {
|
|
||||||
Core.update(deltaTime); // 更新全局服务
|
|
||||||
sceneManager.update(); // 更新当前场景
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 场景切换
|
|
||||||
|
|
||||||
SceneManager 支持流畅的场景切换:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 立即切换场景
|
|
||||||
const menuScene = new MenuScene();
|
|
||||||
sceneManager.setScene(menuScene);
|
|
||||||
|
|
||||||
// 延迟切换场景(在下一帧切换)
|
|
||||||
const gameScene = new GameScene();
|
|
||||||
sceneManager.startSceneTransition(gameScene, false);
|
|
||||||
|
|
||||||
// 访问当前场景
|
|
||||||
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 });
|
|
||||||
|
|
||||||
// 从服务容器获取 WorldManager(Core 已自动创建并注册)
|
|
||||||
const worldManager = Core.services.resolve(WorldManager);
|
|
||||||
|
|
||||||
// 创建多个独立的游戏世界
|
|
||||||
const gameWorld = worldManager.createWorld('game', {
|
|
||||||
name: 'MainGame',
|
|
||||||
maxScenes: 5
|
|
||||||
});
|
|
||||||
|
|
||||||
// 在World中创建场景
|
|
||||||
const menuScene = gameWorld.createScene('menu', new MenuScene());
|
|
||||||
const gameScene = gameWorld.createScene('game', new GameScene());
|
|
||||||
|
|
||||||
// 激活场景
|
|
||||||
gameWorld.setSceneActive('menu', true);
|
|
||||||
|
|
||||||
// 游戏循环
|
|
||||||
function gameLoop(deltaTime: number) {
|
|
||||||
Core.update(deltaTime); // 更新全局服务
|
|
||||||
worldManager.updateAll(); // 更新所有世界
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 多场景管理
|
|
||||||
|
|
||||||
在World中可以管理多个场景,通过激活/停用来切换:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
class GameWorld extends World {
|
|
||||||
private menuScene: Scene;
|
|
||||||
private gameScene: Scene;
|
|
||||||
private gameOverScene: Scene;
|
|
||||||
|
|
||||||
public initialize(): void {
|
|
||||||
// 创建多个场景
|
|
||||||
this.menuScene = this.createScene('menu', new MenuScene());
|
|
||||||
this.gameScene = this.createScene('game', new GameScene());
|
|
||||||
this.gameOverScene = this.createScene('gameover', new GameOverScene());
|
|
||||||
|
|
||||||
// 设置初始场景
|
|
||||||
this.showMenu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public showMenu(): void {
|
public queryEntities(): void {
|
||||||
this.deactivateAllScenes();
|
// 通过 QuerySystem 查询
|
||||||
this.setSceneActive('menu', true);
|
const entities = this.querySystem.query([Transform, Velocity]);
|
||||||
}
|
console.log(`找到 ${entities.length} 个有 Transform 和 Velocity 的实体`);
|
||||||
|
|
||||||
public startGame(): void {
|
// 使用 ECS 流式 API(如果通过 SceneManager)
|
||||||
this.deactivateAllScenes();
|
// const api = sceneManager.api;
|
||||||
this.setSceneActive('game', true);
|
// const entities = api?.find(Transform, Velocity);
|
||||||
}
|
|
||||||
|
|
||||||
public showGameOver(): void {
|
|
||||||
this.deactivateAllScenes();
|
|
||||||
this.setSceneActive('gameover', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private deactivateAllScenes(): void {
|
|
||||||
this.setSceneActive('menu', false);
|
|
||||||
this.setSceneActive('game', false);
|
|
||||||
this.setSceneActive('gameover', false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 架构层次
|
## 性能监控
|
||||||
|
|
||||||
ECS Framework 的架构层次清晰,职责分明:
|
Scene 内置了性能监控功能:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 架构层次:
|
class PerformanceScene extends Scene {
|
||||||
// Core (全局服务) → SceneManager (场景管理) → Scene → EntitySystem → Entity → Component
|
public showPerformance(): void {
|
||||||
// 或
|
// 获取性能数据
|
||||||
// Core (全局服务) → WorldManager (世界管理) → World → Scene → EntitySystem → Entity → Component
|
const perfData = this.performanceMonitor?.getPerformanceData();
|
||||||
|
if (perfData) {
|
||||||
|
console.log('FPS:', perfData.fps);
|
||||||
|
console.log('帧时间:', perfData.frameTime);
|
||||||
|
console.log('实体更新时间:', perfData.entityUpdateTime);
|
||||||
|
console.log('系统更新时间:', perfData.systemUpdateTime);
|
||||||
|
}
|
||||||
|
|
||||||
// 1. 推荐:使用 SceneManager 管理单场景/场景切换
|
// 获取性能报告
|
||||||
import { Core, SceneManager } from '@esengine/ecs-framework';
|
const report = this.performanceMonitor?.generateReport();
|
||||||
|
if (report) {
|
||||||
Core.create({ debug: true });
|
console.log('性能报告:', report);
|
||||||
const sceneManager = Core.services.resolve(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 = Core.services.resolve(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(); // 所有世界更新
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -465,7 +397,7 @@ function gameLoop(deltaTime: number) {
|
|||||||
### 1. 场景职责分离
|
### 1. 场景职责分离
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// ✅ 好的场景设计 - 职责清晰
|
// 好的场景设计 - 职责清晰
|
||||||
class MenuScene extends Scene {
|
class MenuScene extends Scene {
|
||||||
// 只处理菜单相关逻辑
|
// 只处理菜单相关逻辑
|
||||||
}
|
}
|
||||||
@@ -478,7 +410,7 @@ class InventoryScene extends Scene {
|
|||||||
// 只处理物品栏逻辑
|
// 只处理物品栏逻辑
|
||||||
}
|
}
|
||||||
|
|
||||||
// ❌ 避免的场景设计 - 职责混乱
|
// 避免的场景设计 - 职责混乱
|
||||||
class MegaScene extends Scene {
|
class MegaScene extends Scene {
|
||||||
// 包含菜单、游戏、物品栏等所有逻辑
|
// 包含菜单、游戏、物品栏等所有逻辑
|
||||||
}
|
}
|
||||||
@@ -525,12 +457,25 @@ class ResourceScene extends Scene {
|
|||||||
|
|
||||||
private loadResources(): void {
|
private loadResources(): void {
|
||||||
// 加载场景所需资源
|
// 加载场景所需资源
|
||||||
|
this.textures.set('player', this.loadTexture('player.png'));
|
||||||
|
this.sounds.set('bgm', this.loadSound('bgm.mp3'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public unload(): void {
|
public unload(): void {
|
||||||
// 清理资源
|
// 清理资源
|
||||||
this.textures.clear();
|
this.textures.clear();
|
||||||
this.sounds.clear();
|
this.sounds.clear();
|
||||||
|
console.log('场景资源已清理');
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadTexture(path: string): any {
|
||||||
|
// 加载纹理
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadSound(path: string): any {
|
||||||
|
// 加载音效
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -571,7 +516,146 @@ class EventHandlingScene extends Scene {
|
|||||||
private onPlayerInput(data: any): void {
|
private onPlayerInput(data: any): void {
|
||||||
// 处理玩家输入
|
// 处理玩家输入
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unload(): void {
|
||||||
|
// 清理事件监听
|
||||||
|
this.eventSystem.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 5. 初始化顺序
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class ProperInitScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
// 1. 首先设置场景配置
|
||||||
|
this.name = "GameScene";
|
||||||
|
|
||||||
|
// 2. 然后添加系统(按依赖顺序)
|
||||||
|
this.addSystem(new InputSystem());
|
||||||
|
this.addSystem(new MovementSystem());
|
||||||
|
this.addSystem(new PhysicsSystem());
|
||||||
|
this.addSystem(new RenderSystem());
|
||||||
|
|
||||||
|
// 3. 最后创建实体
|
||||||
|
this.createEntities();
|
||||||
|
|
||||||
|
// 4. 设置事件监听
|
||||||
|
this.setupEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private createEntities(): void {
|
||||||
|
// 创建实体
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupEvents(): void {
|
||||||
|
// 设置事件监听
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Scene, EntitySystem, Entity, Matcher } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 定义组件
|
||||||
|
class Transform {
|
||||||
|
constructor(public x: number, public y: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Velocity {
|
||||||
|
constructor(public vx: number, public vy: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Health {
|
||||||
|
constructor(public value: number) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义系统
|
||||||
|
class MovementSystem extends EntitySystem {
|
||||||
|
constructor() {
|
||||||
|
super(Matcher.all(Transform, Velocity));
|
||||||
|
}
|
||||||
|
|
||||||
|
process(entities: readonly Entity[]): void {
|
||||||
|
for (const entity of entities) {
|
||||||
|
const transform = entity.getComponent(Transform);
|
||||||
|
const velocity = entity.getComponent(Velocity);
|
||||||
|
|
||||||
|
if (transform && velocity) {
|
||||||
|
transform.x += velocity.vx;
|
||||||
|
transform.y += velocity.vy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义场景
|
||||||
|
class GameScene extends Scene {
|
||||||
|
protected initialize(): void {
|
||||||
|
this.name = "GameScene";
|
||||||
|
|
||||||
|
// 添加系统
|
||||||
|
this.addSystem(new MovementSystem());
|
||||||
|
|
||||||
|
// 创建玩家
|
||||||
|
const player = this.createEntity("Player");
|
||||||
|
player.addComponent(new Transform(400, 300));
|
||||||
|
player.addComponent(new Velocity(0, 0));
|
||||||
|
player.addComponent(new Health(100));
|
||||||
|
|
||||||
|
// 创建敌人
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const enemy = this.createEntity(`Enemy_${i}`);
|
||||||
|
enemy.addComponent(new Transform(
|
||||||
|
Math.random() * 800,
|
||||||
|
Math.random() * 600
|
||||||
|
));
|
||||||
|
enemy.addComponent(new Velocity(
|
||||||
|
Math.random() * 100 - 50,
|
||||||
|
Math.random() * 100 - 50
|
||||||
|
));
|
||||||
|
enemy.addComponent(new Health(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置事件监听
|
||||||
|
this.eventSystem.on('player_died', () => {
|
||||||
|
console.log('玩家死亡!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public onStart(): void {
|
||||||
|
console.log('游戏场景启动');
|
||||||
|
}
|
||||||
|
|
||||||
|
public unload(): void {
|
||||||
|
console.log('游戏场景卸载');
|
||||||
|
this.eventSystem.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用场景
|
||||||
|
// 方式1:通过 SceneManager(推荐)
|
||||||
|
import { Core, SceneManager } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
Core.create({ debug: true });
|
||||||
|
const sceneManager = Core.services.resolve(SceneManager);
|
||||||
|
sceneManager.setScene(new GameScene());
|
||||||
|
|
||||||
|
// 方式2:通过 WorldManager(高级用例)
|
||||||
|
import { WorldManager } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
const worldManager = Core.services.resolve(WorldManager);
|
||||||
|
const world = worldManager.createWorld('game');
|
||||||
|
world.createScene('main', new GameScene());
|
||||||
|
world.setSceneActive('main', true);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 下一步
|
||||||
|
|
||||||
|
- 了解 [SceneManager](./scene-manager.md) - 适用于大多数游戏的简单场景管理
|
||||||
|
- 了解 [WorldManager](./world-manager.md) - 适用于需要多世界隔离的高级场景
|
||||||
|
|
||||||
场景是 ECS 框架的核心容器,正确使用场景管理能让你的游戏架构更加清晰、模块化和易于维护。
|
场景是 ECS 框架的核心容器,正确使用场景管理能让你的游戏架构更加清晰、模块化和易于维护。
|
||||||
761
docs/guide/world-manager.md
Normal file
761
docs/guide/world-manager.md
Normal file
@@ -0,0 +1,761 @@
|
|||||||
|
# WorldManager
|
||||||
|
|
||||||
|
WorldManager 是 ECS Framework 提供的高级世界管理器,用于管理多个完全隔离的游戏世界(World)。每个 World 都是独立的 ECS 环境,可以包含多个场景。
|
||||||
|
|
||||||
|
## 适用场景
|
||||||
|
|
||||||
|
WorldManager 适合以下高级场景:
|
||||||
|
- MMO 游戏服务器的多房间管理
|
||||||
|
- 游戏大厅系统(每个游戏房间完全隔离)
|
||||||
|
- 服务器端的多游戏实例
|
||||||
|
- 需要完全隔离的多个游戏环境
|
||||||
|
- 需要同时运行多个独立世界的应用
|
||||||
|
|
||||||
|
## 特点
|
||||||
|
|
||||||
|
- 多 World 管理,每个 World 完全独立
|
||||||
|
- 每个 World 可以包含多个 Scene
|
||||||
|
- 支持 World 的激活/停用
|
||||||
|
- 自动清理空 World
|
||||||
|
- World 级别的全局系统
|
||||||
|
- 批量操作和查询
|
||||||
|
|
||||||
|
## 基本使用
|
||||||
|
|
||||||
|
### 初始化
|
||||||
|
|
||||||
|
WorldManager 是 Core 的内置服务,通过服务容器获取:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Core, WorldManager } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 初始化 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
|
||||||
|
import { IGlobalSystem } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 网络系统(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,
|
||||||
|
// cleanupInterval: 30000 // 30 秒
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
### 手动清理
|
||||||
|
|
||||||
|
```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
|
||||||
|
import { Core, WorldManager, Scene, World } from '@esengine/ecs-framework';
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
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)。
|
||||||
Reference in New Issue
Block a user