docs: 更新项目文档 - 添加EntityManager、事件系统、性能优化使用示例和说明
This commit is contained in:
427
README.md
427
README.md
@@ -3,18 +3,17 @@
|
||||
[](https://badge.fury.io/js/%40esengine%2Fecs-framework)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
一个轻量级的 TypeScript ECS(Entity-Component-System)框架,专为小游戏开发设计,适用于 Laya、Cocos 等游戏引擎。
|
||||
一个专业级的 TypeScript ECS(Entity-Component-System)框架,采用现代化架构设计,专为高性能游戏开发打造。
|
||||
|
||||
## ✨ 特性
|
||||
## ✨ 核心特性
|
||||
|
||||
- 🚀 **轻量级 ECS 架构** - 基于实体组件系统,提供清晰的代码结构
|
||||
- ⚡ **高性能** - 实体创建速度可达64万实体/秒,支持大规模实体管理
|
||||
- 🎯 **智能优化** - 组件对象池、位掩码优化器、延迟索引更新等性能优化技术
|
||||
- 📡 **事件系统** - 内置 Emitter 事件发射器,支持类型安全的事件管理
|
||||
- ⏰ **定时器系统** - 完整的定时器管理,支持延迟和重复任务
|
||||
- 🔍 **查询系统** - 基于位掩码的高性能实体查询,支持批量操作
|
||||
- 🛠️ **性能监控** - 内置性能监控工具,帮助优化游戏性能
|
||||
- 🔧 **批量操作** - 支持批量实体创建、组件添加等高效操作
|
||||
- 🏗️ **现代化 ECS 架构** - 完整的实体组件系统,提供清晰的代码结构
|
||||
- 📡 **类型安全事件系统** - 增强的事件总线,支持异步事件、优先级、批处理和装饰器
|
||||
- ⏰ **定时器管理系统** - 完整的定时器管理,支持延迟和重复任务
|
||||
- 🔍 **智能查询系统** - 支持复杂的实体查询,流式API设计
|
||||
- ⚡ **高性能优化** - 组件索引、Archetype系统、脏标记机制三重优化
|
||||
- 🛠️ **开发者友好** - 完整的TypeScript支持,丰富的调试工具
|
||||
- 📦 **轻量级设计** - 最小化依赖,适用于各种游戏引擎
|
||||
|
||||
## 📦 安装
|
||||
|
||||
@@ -22,162 +21,194 @@
|
||||
npm install @esengine/ecs-framework
|
||||
```
|
||||
|
||||
## 📊 性能基准
|
||||
|
||||
```bash
|
||||
# 运行快速性能基准测试
|
||||
npm run benchmark
|
||||
|
||||
# 运行完整性能测试
|
||||
npm run test:performance
|
||||
```
|
||||
|
||||
**框架性能数据**:
|
||||
|
||||
### 🚀 实体创建性能
|
||||
- **小规模**: 640,697 实体/秒 (1,000个实体/1.56ms)
|
||||
- **中规模**: 250,345 实体/秒 (10,000个实体/39.94ms)
|
||||
- **大规模**: 161,990 实体/秒 (500,000个实体/3.09秒)
|
||||
|
||||
### 🎯 核心操作性能
|
||||
```
|
||||
📊 核心操作性能
|
||||
实体创建: 640,697个/秒
|
||||
组件添加: 596,929组件/秒
|
||||
位掩码操作: 5,000,000次/秒
|
||||
查询缓存: 零延迟访问
|
||||
批量操作: 高效处理
|
||||
|
||||
🔧 优化技术效果
|
||||
组件对象池: 减少30-50%内存分配
|
||||
位掩码优化器: 提升20-40%掩码性能
|
||||
批量操作: 大幅减少创建时间
|
||||
索引优化: 避免O(n)重复检查
|
||||
缓存策略: 延迟清理机制
|
||||
```
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 初始化框架
|
||||
### 1. 基础设置
|
||||
|
||||
```typescript
|
||||
import { Core, CoreEvents } from '@esengine/ecs-framework';
|
||||
import { Core, CoreEvents, Scene } from '@esengine/ecs-framework';
|
||||
|
||||
// 创建 Core 实例
|
||||
const core = Core.create(true); // true 表示开启调试模式
|
||||
const core = Core.create(true); // 开启调试模式
|
||||
|
||||
// 创建场景
|
||||
class GameScene extends Scene {
|
||||
public initialize() {
|
||||
// 场景初始化逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 在游戏循环中更新框架
|
||||
function gameLoop() {
|
||||
// 发送帧更新事件
|
||||
Core.emitter.emit(CoreEvents.frameUpdated);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 高性能批量创建实体
|
||||
### 2. 创建实体和组件
|
||||
|
||||
```typescript
|
||||
import { Scene, EntitySystem } from '@esengine/ecs-framework';
|
||||
import { Component, Entity } from '@esengine/ecs-framework';
|
||||
|
||||
class GameScene extends Scene {
|
||||
public initialize() {
|
||||
// 批量创建实体
|
||||
const entities = this.createEntities(1000, "Enemy");
|
||||
|
||||
// 批量添加组件
|
||||
entities.forEach((entity, index) => {
|
||||
entity.addComponent(new PositionComponent(
|
||||
Math.random() * 1000,
|
||||
Math.random() * 1000
|
||||
));
|
||||
entity.addComponent(new VelocityComponent());
|
||||
});
|
||||
|
||||
// 添加系统
|
||||
this.addEntityProcessor(new MovementSystem());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 使用组件对象池优化内存
|
||||
|
||||
```typescript
|
||||
import { Component, ComponentPoolManager } from '@esengine/ecs-framework';
|
||||
|
||||
class BulletComponent extends Component {
|
||||
public damage: number = 10;
|
||||
public speed: number = 300;
|
||||
|
||||
// 重置方法用于对象池
|
||||
public reset() {
|
||||
this.damage = 10;
|
||||
this.speed = 300;
|
||||
// 定义组件
|
||||
class PositionComponent extends Component {
|
||||
constructor(public x: number = 0, public y: number = 0) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
// 注册组件池
|
||||
ComponentPoolManager.getInstance().registerPool(BulletComponent, 1000);
|
||||
class VelocityComponent extends Component {
|
||||
constructor(public dx: number = 0, public dy: number = 0) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
// 使用对象池获取组件
|
||||
const bullet = ComponentPoolManager.getInstance().getComponent(BulletComponent);
|
||||
entity.addComponent(bullet);
|
||||
|
||||
// 释放回对象池
|
||||
ComponentPoolManager.getInstance().releaseComponent(bullet);
|
||||
// 创建实体
|
||||
const entity = scene.createEntity("Player");
|
||||
entity.addComponent(new PositionComponent(100, 100));
|
||||
entity.addComponent(new VelocityComponent(10, 0));
|
||||
```
|
||||
|
||||
### 4. 位掩码优化器加速查询
|
||||
### 3. 创建处理系统
|
||||
|
||||
```typescript
|
||||
import { BitMaskOptimizer } from '@esengine/ecs-framework';
|
||||
import { EntitySystem } from '@esengine/ecs-framework';
|
||||
|
||||
// 注册常用组件类型
|
||||
const optimizer = BitMaskOptimizer.getInstance();
|
||||
optimizer.registerComponentType(PositionComponent);
|
||||
optimizer.registerComponentType(VelocityComponent);
|
||||
optimizer.registerComponentType(RenderComponent);
|
||||
class MovementSystem extends EntitySystem {
|
||||
public process(entities: Entity[]) {
|
||||
for (const entity of entities) {
|
||||
const position = entity.getComponent(PositionComponent);
|
||||
const velocity = entity.getComponent(VelocityComponent);
|
||||
|
||||
// 预计算常用掩码组合
|
||||
optimizer.precomputeCommonMasks();
|
||||
if (position && velocity) {
|
||||
position.x += velocity.dx;
|
||||
position.y += velocity.dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 高效的掩码操作
|
||||
const positionMask = optimizer.getComponentMask(PositionComponent);
|
||||
const movementMask = optimizer.getCombinedMask([PositionComponent, VelocityComponent]);
|
||||
// 添加系统到场景
|
||||
scene.addEntityProcessor(new MovementSystem());
|
||||
```
|
||||
|
||||
### 4. 实体查询和管理
|
||||
|
||||
```typescript
|
||||
import { EntityManager } from '@esengine/ecs-framework';
|
||||
|
||||
// 使用EntityManager进行高级查询
|
||||
const entityManager = new EntityManager();
|
||||
|
||||
// 查询具有特定组件的实体
|
||||
const movingEntities = entityManager
|
||||
.query()
|
||||
.withAll(PositionComponent, VelocityComponent)
|
||||
.execute();
|
||||
|
||||
// 查询带标签的实体
|
||||
const enemies = entityManager.getEntitiesByTag(1);
|
||||
|
||||
// 批量创建实体
|
||||
const bullets = entityManager.createEntities(100, "bullet");
|
||||
```
|
||||
|
||||
### 5. 事件系统
|
||||
|
||||
```typescript
|
||||
import { EventBus, ECSEventType, EventHandler } from '@esengine/ecs-framework';
|
||||
|
||||
// 获取事件总线
|
||||
const eventBus = entityManager.eventBus;
|
||||
|
||||
// 监听实体创建事件
|
||||
eventBus.onEntityCreated((data) => {
|
||||
console.log(`Entity created: ${data.entityName}`);
|
||||
});
|
||||
|
||||
// 监听组件添加事件
|
||||
eventBus.onComponentAdded((data) => {
|
||||
console.log(`Component ${data.componentType} added to entity ${data.entityId}`);
|
||||
});
|
||||
|
||||
// 使用装饰器自动注册事件监听器
|
||||
class GameManager {
|
||||
@EventHandler(ECSEventType.ENTITY_DESTROYED)
|
||||
onEntityDestroyed(data) {
|
||||
console.log('Entity destroyed:', data.entityName);
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义事件
|
||||
eventBus.emit('player:levelup', { playerId: 123, newLevel: 5 });
|
||||
```
|
||||
|
||||
## 🆚 框架对比
|
||||
|
||||
与其他 TypeScript ECS 框架相比,我们的优势:
|
||||
|
||||
| 特性 | @esengine/ecs-framework | bitecs | ecsy | Miniplex |
|
||||
|------|-------------------------|-------|------|----------|
|
||||
| **TypeScript 支持** | ✅ 原生支持 | ✅ 完整支持 | ⚠️ 部分支持 | ✅ 原生支持 |
|
||||
| **事件系统** | ✅ 类型安全+装饰器 | ❌ 无内置事件系统 | ⚠️ 基础事件 | ✅ 响应式事件 |
|
||||
| **查询系统** | ✅ 智能查询+流式API | ✅ 高性能 | ✅ 基础查询 | ✅ 响应式查询 |
|
||||
| **性能优化** | ✅ 多层优化系统 | ✅ WASM优化 | ⚠️ 基础优化 | ✅ React集成优化 |
|
||||
| **实体管理器** | ✅ 统一管理接口 | ❌ 无统一接口 | ✅ 基础管理 | ✅ 响应式管理 |
|
||||
| **组件索引** | ✅ 哈希+位图索引 | ✅ 原生支持 | ❌ 无索引系统 | ✅ 自动索引 |
|
||||
| **Archetype系统** | ✅ 内置支持 | ✅ 内置支持 | ❌ 无Archetype | ❌ 无Archetype |
|
||||
| **脏标记系统** | ✅ 细粒度追踪 | ⚠️ 基础支持 | ❌ 无脏标记 | ✅ React级追踪 |
|
||||
| **批量操作** | ✅ 全面的批量API | ✅ 批量支持 | ⚠️ 有限支持 | ⚠️ 有限支持 |
|
||||
| **游戏引擎集成** | ✅ 通用设计 | ✅ 通用设计 | ✅ 通用设计 | ⚠️ 主要针对React |
|
||||
| **学习曲线** | 🟢 中等 | 🟡 较陡峭 | 🟢 简单 | 🟡 需要React知识 |
|
||||
| **社区生态** | 🟡 成长中 | 🟢 活跃 | 🟡 稳定 | 🟡 小众但精品 |
|
||||
|
||||
### 为什么选择我们?
|
||||
|
||||
**相比 bitecs**:
|
||||
- 更友好的 TypeScript API,无需手动管理内存
|
||||
- 完整的实体管理器,开发体验更佳
|
||||
- 内置类型安全事件系统,bitecs需要自己实现
|
||||
- 多种索引系统可选,适应不同场景
|
||||
|
||||
**相比 ecsy**:
|
||||
- 现代化的性能优化系统(组件索引、Archetype、脏标记)
|
||||
- 更完整的 TypeScript 类型定义
|
||||
- 增强的事件系统,支持装饰器和异步事件
|
||||
- 活跃的维护和功能更新
|
||||
|
||||
**相比 Miniplex**:
|
||||
- 不依赖 React 生态,可用于任何游戏引擎
|
||||
- 专门针对游戏开发优化
|
||||
- 更轻量级的核心设计
|
||||
- 传统事件模式,更适合游戏开发习惯
|
||||
|
||||
## 📚 核心概念
|
||||
|
||||
### Entity(实体)
|
||||
实体是游戏世界中的基本对象,支持批量操作和高性能创建。
|
||||
实体是游戏世界中的基本对象,可以挂载组件和运行系统。
|
||||
|
||||
```typescript
|
||||
// 单个实体创建
|
||||
const entity = scene.createEntity("MyEntity");
|
||||
// 创建实体
|
||||
const entity = scene.createEntity("Player");
|
||||
|
||||
// 批量实体创建
|
||||
const entities = scene.createEntities(1000, "Bullets");
|
||||
|
||||
// 实体属性设置
|
||||
// 设置实体属性
|
||||
entity.tag = 1;
|
||||
entity.updateOrder = 0;
|
||||
entity.enabled = true;
|
||||
|
||||
// 批量创建实体
|
||||
const entities = scene.createEntities(100, "Enemy");
|
||||
```
|
||||
|
||||
### Component(组件)
|
||||
组件包含数据和行为,支持对象池优化。
|
||||
组件存储数据,定义实体的属性和状态。
|
||||
|
||||
```typescript
|
||||
import { Component, ComponentPoolManager } from '@esengine/ecs-framework';
|
||||
import { Component } from '@esengine/ecs-framework';
|
||||
|
||||
class HealthComponent extends Component {
|
||||
public maxHealth: number = 100;
|
||||
public currentHealth: number = 100;
|
||||
|
||||
// 对象池重置方法
|
||||
public reset() {
|
||||
this.maxHealth = 100;
|
||||
this.currentHealth = 100;
|
||||
}
|
||||
|
||||
public takeDamage(damage: number) {
|
||||
this.currentHealth = Math.max(0, this.currentHealth - damage);
|
||||
if (this.currentHealth <= 0) {
|
||||
@@ -186,30 +217,22 @@ class HealthComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// 注册到对象池
|
||||
ComponentPoolManager.getInstance().registerPool(HealthComponent, 500);
|
||||
// 添加组件到实体
|
||||
entity.addComponent(new HealthComponent());
|
||||
```
|
||||
|
||||
### System(系统)
|
||||
系统处理实体集合,支持批量处理优化。
|
||||
系统处理具有特定组件的实体集合,实现游戏逻辑。
|
||||
|
||||
```typescript
|
||||
import { EntitySystem, Entity } from '@esengine/ecs-framework';
|
||||
|
||||
class HealthSystem extends EntitySystem {
|
||||
protected process(entities: Entity[]) {
|
||||
// 批量处理实体
|
||||
const batchSize = 1000;
|
||||
for (let i = 0; i < entities.length; i += batchSize) {
|
||||
const batch = entities.slice(i, i + batchSize);
|
||||
this.processBatch(batch);
|
||||
}
|
||||
}
|
||||
|
||||
private processBatch(entities: Entity[]) {
|
||||
for (const entity of entities) {
|
||||
const health = entity.getComponent(HealthComponent);
|
||||
if (health && health.currentHealth <= 0) {
|
||||
// 处理实体死亡逻辑
|
||||
entity.destroy();
|
||||
}
|
||||
}
|
||||
@@ -217,130 +240,22 @@ class HealthSystem extends EntitySystem {
|
||||
}
|
||||
```
|
||||
|
||||
## 🎮 高级功能
|
||||
|
||||
### 批量操作API
|
||||
|
||||
```typescript
|
||||
// 批量创建实体
|
||||
const entities = scene.createEntities(5000, "Enemies");
|
||||
|
||||
// 批量查询
|
||||
const movingEntities = scene.getEntitiesWithComponents([PositionComponent, VelocityComponent]);
|
||||
|
||||
// 延迟缓存清理
|
||||
scene.addEntity(entity, false); // 延迟缓存清理
|
||||
// ... 添加更多实体
|
||||
scene.querySystem.clearCache(); // 手动清理缓存
|
||||
```
|
||||
|
||||
### 性能监控
|
||||
|
||||
```typescript
|
||||
import { Core } from '@esengine/ecs-framework';
|
||||
|
||||
// 获取性能统计
|
||||
const stats = scene.getPerformanceStats();
|
||||
console.log(`实体数量: ${stats.entityCount}`);
|
||||
console.log(`查询缓存大小: ${stats.queryCacheSize}`);
|
||||
console.log(`组件池统计:`, stats.componentPoolStats);
|
||||
```
|
||||
|
||||
### 内存优化
|
||||
|
||||
```typescript
|
||||
// 预热组件池
|
||||
ComponentPoolManager.getInstance().preWarmPools({
|
||||
BulletComponent: 1000,
|
||||
EffectComponent: 500,
|
||||
PickupComponent: 200
|
||||
});
|
||||
|
||||
// 清理未使用的组件
|
||||
ComponentPoolManager.getInstance().clearUnusedComponents();
|
||||
```
|
||||
|
||||
## 🧪 测试和基准
|
||||
|
||||
### 运行测试套件
|
||||
## 🧪 测试
|
||||
|
||||
```bash
|
||||
# 运行所有测试
|
||||
npm run test
|
||||
|
||||
# 单元测试
|
||||
npm run test:unit
|
||||
|
||||
# 性能测试
|
||||
npm run test:performance
|
||||
|
||||
# 快速基准测试
|
||||
# 性能基准测试
|
||||
npm run benchmark
|
||||
```
|
||||
|
||||
### 自定义性能测试
|
||||
|
||||
```typescript
|
||||
import { runEntityCreationBenchmark } from './Testing/Performance/benchmark';
|
||||
|
||||
// 运行自定义基准测试
|
||||
await runEntityCreationBenchmark();
|
||||
```
|
||||
|
||||
## 🔧 优化建议
|
||||
|
||||
### 大规模实体处理
|
||||
|
||||
1. **使用批量API**
|
||||
```typescript
|
||||
// ✅ 推荐:批量创建
|
||||
const entities = scene.createEntities(10000, "Units");
|
||||
|
||||
// ❌ 避免:循环单个创建
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
scene.createEntity("Unit" + i);
|
||||
}
|
||||
```
|
||||
|
||||
2. **启用对象池**
|
||||
```typescript
|
||||
// 预先注册常用组件池
|
||||
ComponentPoolManager.getInstance().registerPool(BulletComponent, 2000);
|
||||
ComponentPoolManager.getInstance().registerPool(EffectComponent, 1000);
|
||||
```
|
||||
|
||||
3. **优化查询频率**
|
||||
```typescript
|
||||
// 缓存查询结果
|
||||
if (frameCount % 5 === 0) {
|
||||
this.cachedEnemies = scene.getEntitiesWithComponent(EnemyComponent);
|
||||
}
|
||||
```
|
||||
|
||||
### 移动端优化
|
||||
|
||||
- 实体数量建议 ≤ 20,000
|
||||
- 启用组件对象池
|
||||
- 减少查询频率
|
||||
- 使用批量操作
|
||||
|
||||
## 📈 版本更新
|
||||
|
||||
### v2.0.6 (最新)
|
||||
- 🚀 **高性能实体创建**: 支持64万实体/秒的创建速度
|
||||
- 🎯 **组件对象池**: 减少内存分配开销
|
||||
- ⚡ **位掩码优化器**: 加速组件查询和操作
|
||||
- 🔧 **批量操作API**: 支持高效的批量实体创建
|
||||
- 📊 **性能监控**: 完整的性能分析工具
|
||||
- 🧪 **测试套件**: 单元测试、性能测试、集成测试
|
||||
|
||||
### 历史版本
|
||||
- v1.x.x: 基础ECS架构实现
|
||||
|
||||
## 📖 文档
|
||||
|
||||
- [快速入门](docs/getting-started.md) - 从零开始学习框架使用
|
||||
- [实体使用指南](docs/entity-guide.md) - 详细了解实体的所有功能和用法
|
||||
- [EntityManager 使用指南](docs/entity-manager-example.md) - 详细了解实体管理器的高级功能
|
||||
- [事件系统使用指南](docs/event-system-example.md) - 学习类型安全事件系统的完整用法
|
||||
- [性能优化指南](docs/performance-optimization.md) - 深入了解三大性能优化系统
|
||||
- [核心概念](docs/core-concepts.md) - 深入了解 ECS 架构和设计原理
|
||||
- [查询系统使用指南](docs/query-system-usage.md) - 学习高性能查询系统的详细用法
|
||||
|
||||
@@ -380,6 +295,32 @@ cd source && npm install && npm run build
|
||||
|
||||
加入 QQ 群讨论:[ecs游戏框架交流](https://jq.qq.com/?_wv=1027&k=29w1Nud6)
|
||||
|
||||
### 🚀 核心性能指标
|
||||
|
||||
```bash
|
||||
实体创建: 640,000+ 个/秒
|
||||
组件查询: O(1) 复杂度(使用索引)
|
||||
内存优化: 30-50% 减少分配
|
||||
批量操作: 显著提升处理效率
|
||||
```
|
||||
|
||||
### 🎯 性能优化技术
|
||||
|
||||
- **组件索引系统**: 哈希和位图双重索引,支持 O(1) 查询
|
||||
- **Archetype 系统**: 按组件组合分组,减少查询开销
|
||||
- **脏标记机制**: 细粒度变更追踪,避免不必要的计算
|
||||
- **批量操作 API**: 减少函数调用开销,提升大规模操作效率
|
||||
- **智能缓存**: 查询结果缓存和延迟清理机制
|
||||
|
||||
### 🔧 性能建议
|
||||
|
||||
1. **大规模场景**: 使用批量API和组件索引
|
||||
2. **频繁查询**: 启用Archetype系统进行快速筛选
|
||||
3. **实时游戏**: 利用脏标记减少无效更新
|
||||
4. **移动端**: 建议实体数量控制在20,000以内
|
||||
|
||||
运行 `npm run benchmark` 查看在您的环境中的具体性能表现。
|
||||
|
||||
---
|
||||
|
||||
**ECS Framework** - 让游戏开发更简单、更高效!
|
||||
421
docs/entity-manager-example.md
Normal file
421
docs/entity-manager-example.md
Normal file
@@ -0,0 +1,421 @@
|
||||
# EntityManager 使用指南
|
||||
|
||||
EntityManager 是 ECS Framework 的核心管理系统,提供统一的实体管理、高性能查询和自动优化功能。
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 创建实体管理器
|
||||
|
||||
```typescript
|
||||
import { EntityManager, Scene } from '@esengine/ecs-framework';
|
||||
|
||||
// 通常在游戏管理器中创建
|
||||
const scene = new Scene();
|
||||
const entityManager = new EntityManager(scene);
|
||||
```
|
||||
|
||||
### 基础实体操作
|
||||
|
||||
```typescript
|
||||
// 创建单个实体
|
||||
const player = entityManager.createEntity("Player");
|
||||
player.addComponent(new PositionComponent(100, 100));
|
||||
player.addComponent(new HealthComponent(100));
|
||||
player.tag = "player";
|
||||
|
||||
// 批量创建实体
|
||||
const enemies = entityManager.createEntities(50, "Enemy");
|
||||
enemies.forEach((enemy, index) => {
|
||||
enemy.addComponent(new PositionComponent(
|
||||
Math.random() * 800,
|
||||
Math.random() * 600
|
||||
));
|
||||
enemy.addComponent(new HealthComponent(30));
|
||||
enemy.tag = "enemy";
|
||||
});
|
||||
|
||||
// 销毁实体
|
||||
entityManager.destroyEntity(player);
|
||||
```
|
||||
|
||||
## 高性能查询系统
|
||||
|
||||
EntityManager 提供多种查询方式,自动选择最优的查询策略。
|
||||
|
||||
### 基础查询
|
||||
|
||||
```typescript
|
||||
// 通过ID查询(O(1))
|
||||
const entity = entityManager.getEntity(123);
|
||||
|
||||
// 通过名称查询(O(1) 哈希查找)
|
||||
const player = entityManager.getEntityByName("Player");
|
||||
|
||||
// 通过标签查询(O(1) 索引查找)
|
||||
const enemies = entityManager.getEntitiesByTag("enemy");
|
||||
|
||||
// 组件查询(使用O(1)组件索引)
|
||||
const healthEntities = entityManager.getEntitiesWithComponent(HealthComponent);
|
||||
|
||||
// 多组件查询(使用Archetype优化)
|
||||
const movingEntities = entityManager.getEntitiesWithComponents([
|
||||
PositionComponent,
|
||||
VelocityComponent
|
||||
]);
|
||||
```
|
||||
|
||||
### 流式查询API
|
||||
|
||||
EntityManager 提供强大的流式查询构建器:
|
||||
|
||||
```typescript
|
||||
// 基础查询构建
|
||||
const results = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, HealthComponent]) // 必须包含这些组件
|
||||
.withoutTag("dead") // 不能有死亡标签
|
||||
.active(true) // 必须激活
|
||||
.execute();
|
||||
|
||||
// 复杂条件查询
|
||||
const livingEnemies = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, HealthComponent])
|
||||
.withTag("enemy")
|
||||
.withoutTag("dead")
|
||||
.where(entity => {
|
||||
const health = entity.getComponent(HealthComponent);
|
||||
return health && health.currentHealth > 0;
|
||||
})
|
||||
.execute();
|
||||
|
||||
// 查询变体
|
||||
const firstEnemy = entityManager
|
||||
.query()
|
||||
.withTag("enemy")
|
||||
.first(); // 获取第一个匹配
|
||||
|
||||
const enemyCount = entityManager
|
||||
.query()
|
||||
.withTag("enemy")
|
||||
.count(); // 获取数量
|
||||
|
||||
// 直接处理查询结果
|
||||
entityManager
|
||||
.query()
|
||||
.withAll([HealthComponent])
|
||||
.forEach(entity => {
|
||||
const health = entity.getComponent(HealthComponent);
|
||||
if (health.currentHealth <= 0) {
|
||||
entity.addTag("dead");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 高级查询选项
|
||||
|
||||
```typescript
|
||||
// 组合条件查询
|
||||
const combatUnits = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, HealthComponent]) // AND条件
|
||||
.withAny([WeaponComponent, MagicComponent]) // OR条件
|
||||
.without([DeadComponent]) // NOT条件
|
||||
.withTag("combatant")
|
||||
.withoutTag("peaceful")
|
||||
.active(true)
|
||||
.enabled(true)
|
||||
.execute();
|
||||
|
||||
// 使用自定义过滤器
|
||||
const nearbyEnemies = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent])
|
||||
.withTag("enemy")
|
||||
.where(entity => {
|
||||
const pos = entity.getComponent(PositionComponent);
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(pos.x - playerPos.x, 2) +
|
||||
Math.pow(pos.y - playerPos.y, 2)
|
||||
);
|
||||
return distance < 100; // 距离玩家100像素内
|
||||
})
|
||||
.execute();
|
||||
```
|
||||
|
||||
## 批量操作
|
||||
|
||||
EntityManager 提供高效的批量操作方法:
|
||||
|
||||
```typescript
|
||||
// 遍历所有实体
|
||||
entityManager.forEachEntity(entity => {
|
||||
// 处理每个实体
|
||||
if (entity.position.x < 0) {
|
||||
entity.position.x = 0;
|
||||
}
|
||||
});
|
||||
|
||||
// 遍历特定组件的实体
|
||||
entityManager.forEachEntityWithComponent(HealthComponent, (entity, health) => {
|
||||
if (health.currentHealth <= 0) {
|
||||
entity.addTag("dead");
|
||||
entity.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 批量创建并配置实体
|
||||
const bullets = entityManager.createEntities(100, "Bullet", (bullet, index) => {
|
||||
bullet.addComponent(new PositionComponent(
|
||||
100 + index * 10,
|
||||
100
|
||||
));
|
||||
bullet.addComponent(new VelocityComponent(0, -200));
|
||||
bullet.tag = "projectile";
|
||||
});
|
||||
```
|
||||
|
||||
## 性能优化系统
|
||||
|
||||
EntityManager 内置了三个性能优化系统:
|
||||
|
||||
### 1. 组件索引系统
|
||||
|
||||
自动为组件查询提供O(1)性能:
|
||||
|
||||
```typescript
|
||||
// 获取组件索引统计
|
||||
const componentIndex = entityManager.getComponentIndex();
|
||||
const stats = componentIndex.getPerformanceStats();
|
||||
|
||||
console.log('组件索引统计:', {
|
||||
totalQueries: stats.totalQueries,
|
||||
indexHits: stats.indexHits,
|
||||
hitRate: (stats.indexHits / stats.totalQueries * 100).toFixed(2) + '%'
|
||||
});
|
||||
|
||||
// 手动优化(通常自动进行)
|
||||
componentIndex.optimize();
|
||||
```
|
||||
|
||||
### 2. Archetype系统
|
||||
|
||||
按组件组合分组实体,优化批量查询:
|
||||
|
||||
```typescript
|
||||
// 获取Archetype统计
|
||||
const archetypeSystem = entityManager.getArchetypeSystem();
|
||||
const archetypeStats = archetypeSystem.getStatistics();
|
||||
|
||||
console.log('Archetype统计:', {
|
||||
totalArchetypes: archetypeStats.totalArchetypes,
|
||||
totalEntities: archetypeStats.totalEntities,
|
||||
queryCacheSize: archetypeStats.queryCacheSize
|
||||
});
|
||||
|
||||
// 查看所有原型
|
||||
console.log('当前原型:', archetypeSystem.getAllArchetypes());
|
||||
```
|
||||
|
||||
### 3. 脏标记系统
|
||||
|
||||
追踪实体变更,避免不必要的更新:
|
||||
|
||||
```typescript
|
||||
// 获取脏标记统计
|
||||
const dirtyTracking = entityManager.getDirtyTrackingSystem();
|
||||
const dirtyStats = dirtyTracking.getPerformanceStats();
|
||||
|
||||
console.log('脏标记统计:', {
|
||||
totalMarks: dirtyStats.totalMarks,
|
||||
batchesProcessed: dirtyStats.batchesProcessed,
|
||||
listenersNotified: dirtyStats.listenersNotified
|
||||
});
|
||||
|
||||
// 手动处理脏标记
|
||||
dirtyTracking.processDirtyMarks();
|
||||
```
|
||||
|
||||
## 实体管理器统计
|
||||
|
||||
获取EntityManager的综合性能数据:
|
||||
|
||||
```typescript
|
||||
const stats = entityManager.getStatistics();
|
||||
|
||||
console.log('EntityManager统计:', {
|
||||
// 基础统计
|
||||
entityCount: stats.entityCount,
|
||||
activeEntityCount: stats.activeEntityCount,
|
||||
|
||||
// 查询统计
|
||||
totalQueries: stats.totalQueries,
|
||||
indexHits: stats.indexHits,
|
||||
archetypeHits: stats.archetypeHits,
|
||||
|
||||
// 性能指标
|
||||
averageQueryTime: stats.averageQueryTime,
|
||||
hitRate: (stats.indexHits / stats.totalQueries * 100).toFixed(2) + '%'
|
||||
});
|
||||
```
|
||||
|
||||
## 系统优化和清理
|
||||
|
||||
```typescript
|
||||
// 手动触发优化
|
||||
entityManager.optimize();
|
||||
|
||||
// 内存清理
|
||||
entityManager.cleanup();
|
||||
|
||||
// 压缩数据结构
|
||||
entityManager.compact();
|
||||
|
||||
// 获取内存使用情况
|
||||
const memoryStats = entityManager.getMemoryUsage();
|
||||
console.log('内存使用:', {
|
||||
entityIndexSize: memoryStats.entityIndex,
|
||||
componentIndexSize: memoryStats.componentIndex,
|
||||
archetypeSize: memoryStats.archetype
|
||||
});
|
||||
```
|
||||
|
||||
## 实际使用案例
|
||||
|
||||
### 游戏系统集成
|
||||
|
||||
```typescript
|
||||
class MovementSystem extends EntitySystem {
|
||||
private entityManager: EntityManager;
|
||||
|
||||
constructor(scene: Scene) {
|
||||
super();
|
||||
this.entityManager = new EntityManager(scene);
|
||||
}
|
||||
|
||||
protected process(entities: Entity[]): void {
|
||||
// 使用高效查询获取移动实体
|
||||
const movingEntities = this.entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, VelocityComponent])
|
||||
.active(true)
|
||||
.execute();
|
||||
|
||||
// 批量处理
|
||||
movingEntities.forEach(entity => {
|
||||
const position = entity.getComponent(PositionComponent);
|
||||
const velocity = entity.getComponent(VelocityComponent);
|
||||
|
||||
position.x += velocity.dx * Time.deltaTime;
|
||||
position.y += velocity.dy * Time.deltaTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 复杂查询示例
|
||||
|
||||
```typescript
|
||||
// 战斗系统:查找攻击范围内的敌人
|
||||
class CombatSystem {
|
||||
private entityManager: EntityManager;
|
||||
|
||||
findTargetsInRange(attacker: Entity, range: number): Entity[] {
|
||||
const attackerPos = attacker.getComponent(PositionComponent);
|
||||
if (!attackerPos) return [];
|
||||
|
||||
return this.entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, HealthComponent])
|
||||
.withTag("enemy")
|
||||
.withoutTag("dead")
|
||||
.where(entity => {
|
||||
const pos = entity.getComponent(PositionComponent);
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(pos.x - attackerPos.x, 2) +
|
||||
Math.pow(pos.y - attackerPos.y, 2)
|
||||
);
|
||||
return distance <= range;
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
|
||||
// 优化版本:使用空间分区(如果实现了的话)
|
||||
findTargetsInRangeOptimized(attacker: Entity, range: number): Entity[] {
|
||||
// 首先通过空间查询缩小范围
|
||||
const nearbyEntities = this.spatialIndex.queryRange(
|
||||
attackerPos.x - range,
|
||||
attackerPos.y - range,
|
||||
attackerPos.x + range,
|
||||
attackerPos.y + range
|
||||
);
|
||||
|
||||
// 然后使用EntityManager进行精确过滤
|
||||
return this.entityManager
|
||||
.query()
|
||||
.withAll([HealthComponent])
|
||||
.withTag("enemy")
|
||||
.withoutTag("dead")
|
||||
.where(entity => nearbyEntities.includes(entity))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能建议
|
||||
|
||||
### 查询优化
|
||||
|
||||
1. **利用索引**: 优先使用组件查询和标签查询,它们具有O(1)性能
|
||||
2. **减少自定义过滤**: `where()`条件虽然灵活,但会降低性能
|
||||
3. **缓存查询结果**: 对于不经常变化的查询结果,考虑缓存
|
||||
|
||||
```typescript
|
||||
// ✅ 推荐:使用索引查询
|
||||
const enemies = entityManager.getEntitiesByTag("enemy");
|
||||
|
||||
// ⚠️ 谨慎:自定义过滤
|
||||
const enemies = entityManager
|
||||
.query()
|
||||
.where(entity => entity.name.includes("Enemy"))
|
||||
.execute();
|
||||
```
|
||||
|
||||
### 批量操作优化
|
||||
|
||||
```typescript
|
||||
// ✅ 推荐:批量创建
|
||||
const bullets = entityManager.createEntities(100, "Bullet");
|
||||
|
||||
// ❌ 避免:循环单独创建
|
||||
for (let i = 0; i < 100; i++) {
|
||||
entityManager.createEntity("Bullet");
|
||||
}
|
||||
```
|
||||
|
||||
### 内存管理
|
||||
|
||||
```typescript
|
||||
// 定期清理
|
||||
setInterval(() => {
|
||||
entityManager.cleanup();
|
||||
}, 30000); // 每30秒清理一次
|
||||
|
||||
// 监控性能
|
||||
const stats = entityManager.getStatistics();
|
||||
if (stats.indexHits / stats.totalQueries < 0.8) {
|
||||
console.warn('查询命中率较低,考虑优化查询策略');
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
EntityManager 提供了:
|
||||
|
||||
- **统一接口**: 所有实体操作通过一个管理器完成
|
||||
- **自动优化**: 内置三个性能优化系统
|
||||
- **灵活查询**: 从简单的ID查找到复杂的条件查询
|
||||
- **性能监控**: 完整的统计和诊断信息
|
||||
- **批量操作**: 高效的批量处理能力
|
||||
|
||||
通过合理使用EntityManager,您可以构建高性能、可维护的ECS游戏系统。
|
||||
496
docs/event-system-example.md
Normal file
496
docs/event-system-example.md
Normal file
@@ -0,0 +1,496 @@
|
||||
# ECS事件系统使用指南
|
||||
|
||||
本文档介绍如何使用ECS框架的增强事件系统,包括类型安全的事件发布订阅、预定义的ECS事件类型和高级功能。
|
||||
|
||||
## 目录
|
||||
|
||||
1. [基础用法](#基础用法)
|
||||
2. [预定义ECS事件](#预定义ecs事件)
|
||||
3. [事件装饰器](#事件装饰器)
|
||||
4. [高级功能](#高级功能)
|
||||
5. [性能优化](#性能优化)
|
||||
6. [最佳实践](#最佳实践)
|
||||
|
||||
## 基础用法
|
||||
|
||||
### 创建事件总线
|
||||
|
||||
```typescript
|
||||
import { EventBus, GlobalEventBus } from './ECS';
|
||||
|
||||
// 方式1:创建独立的事件总线
|
||||
const eventBus = new EventBus(true); // true启用调试模式
|
||||
|
||||
// 方式2:使用全局事件总线
|
||||
const globalEventBus = GlobalEventBus.getInstance(true);
|
||||
```
|
||||
|
||||
### 基本事件发布订阅
|
||||
|
||||
```typescript
|
||||
// 定义事件数据类型
|
||||
interface PlayerDiedEvent {
|
||||
playerId: number;
|
||||
cause: string;
|
||||
position: { x: number; y: number };
|
||||
}
|
||||
|
||||
// 监听事件
|
||||
const listenerId = eventBus.on<PlayerDiedEvent>('player:died', (data) => {
|
||||
console.log(`Player ${data.playerId} died at (${data.position.x}, ${data.position.y})`);
|
||||
console.log(`Cause: ${data.cause}`);
|
||||
});
|
||||
|
||||
// 发射事件
|
||||
eventBus.emit('player:died', {
|
||||
playerId: 123,
|
||||
cause: 'enemy_attack',
|
||||
position: { x: 100, y: 200 }
|
||||
});
|
||||
|
||||
// 移除监听器
|
||||
eventBus.off('player:died', listenerId);
|
||||
```
|
||||
|
||||
### 一次性事件监听
|
||||
|
||||
```typescript
|
||||
// 只监听一次
|
||||
eventBus.once<PlayerDiedEvent>('player:died', (data) => {
|
||||
console.log('This will only be called once');
|
||||
});
|
||||
```
|
||||
|
||||
### 异步事件处理
|
||||
|
||||
```typescript
|
||||
// 异步事件监听
|
||||
eventBus.onAsync<PlayerDiedEvent>('player:died', async (data) => {
|
||||
await savePlayerDeathToDatabase(data);
|
||||
await updateLeaderboard(data.playerId);
|
||||
});
|
||||
|
||||
// 异步事件发射
|
||||
await eventBus.emitAsync('player:died', playerData);
|
||||
```
|
||||
|
||||
## 预定义ECS事件
|
||||
|
||||
框架提供了完整的ECS事件类型定义,支持实体、组件、系统等核心概念的事件。
|
||||
|
||||
### 实体事件
|
||||
|
||||
```typescript
|
||||
import { ECSEventType, IEntityEventData } from './ECS';
|
||||
|
||||
// 监听实体创建事件
|
||||
eventBus.onEntityCreated((data: IEntityEventData) => {
|
||||
console.log(`Entity created: ${data.entityName} (ID: ${data.entityId})`);
|
||||
});
|
||||
|
||||
// 监听实体销毁事件
|
||||
eventBus.on<IEntityEventData>(ECSEventType.ENTITY_DESTROYED, (data) => {
|
||||
console.log(`Entity destroyed: ${data.entityName}`);
|
||||
});
|
||||
|
||||
// 手动发射实体事件
|
||||
eventBus.emitEntityCreated({
|
||||
timestamp: Date.now(),
|
||||
source: 'GameManager',
|
||||
entityId: 123,
|
||||
entityName: 'Player',
|
||||
entityTag: 'player'
|
||||
});
|
||||
```
|
||||
|
||||
### 组件事件
|
||||
|
||||
```typescript
|
||||
import { IComponentEventData } from './ECS';
|
||||
|
||||
// 监听组件添加事件
|
||||
eventBus.onComponentAdded((data: IComponentEventData) => {
|
||||
console.log(`Component ${data.componentType} added to entity ${data.entityId}`);
|
||||
});
|
||||
|
||||
// 监听组件移除事件
|
||||
eventBus.on<IComponentEventData>(ECSEventType.COMPONENT_REMOVED, (data) => {
|
||||
console.log(`Component ${data.componentType} removed from entity ${data.entityId}`);
|
||||
});
|
||||
```
|
||||
|
||||
### 系统事件
|
||||
|
||||
```typescript
|
||||
import { ISystemEventData } from './ECS';
|
||||
|
||||
// 监听系统错误
|
||||
eventBus.onSystemError((data: ISystemEventData) => {
|
||||
console.error(`System error in ${data.systemName}: ${data.systemType}`);
|
||||
});
|
||||
|
||||
// 监听系统处理开始/结束
|
||||
eventBus.on<ISystemEventData>(ECSEventType.SYSTEM_PROCESSING_START, (data) => {
|
||||
console.log(`System ${data.systemName} started processing`);
|
||||
});
|
||||
```
|
||||
|
||||
### 性能事件
|
||||
|
||||
```typescript
|
||||
import { IPerformanceEventData } from './ECS';
|
||||
|
||||
// 监听性能警告
|
||||
eventBus.onPerformanceWarning((data: IPerformanceEventData) => {
|
||||
console.warn(`Performance warning: ${data.operation} took ${data.executionTime}ms`);
|
||||
});
|
||||
|
||||
// 监听内存使用过高
|
||||
eventBus.on<IPerformanceEventData>(ECSEventType.MEMORY_USAGE_HIGH, (data) => {
|
||||
console.warn(`High memory usage: ${data.memoryUsage}MB`);
|
||||
});
|
||||
```
|
||||
|
||||
## 事件装饰器
|
||||
|
||||
使用装饰器可以自动注册事件监听器,简化代码编写。
|
||||
|
||||
### 基础装饰器
|
||||
|
||||
```typescript
|
||||
import { EventHandler, AsyncEventHandler, EventPriority } from './ECS';
|
||||
|
||||
class GameManager {
|
||||
@EventHandler(ECSEventType.ENTITY_CREATED, { priority: EventPriority.HIGH })
|
||||
onEntityCreated(data: IEntityEventData) {
|
||||
console.log(`New entity: ${data.entityName}`);
|
||||
}
|
||||
|
||||
@AsyncEventHandler(ECSEventType.ENTITY_DESTROYED)
|
||||
async onEntityDestroyed(data: IEntityEventData) {
|
||||
await this.cleanupEntityResources(data.entityId);
|
||||
}
|
||||
|
||||
@EventHandler('custom:game:event', { once: true })
|
||||
onGameStart(data: any) {
|
||||
console.log('Game started!');
|
||||
}
|
||||
|
||||
// 需要手动调用初始化方法
|
||||
constructor() {
|
||||
// 如果类有initEventListeners方法,会自动注册装饰器定义的监听器
|
||||
if (this.initEventListeners) {
|
||||
this.initEventListeners();
|
||||
}
|
||||
}
|
||||
|
||||
private async cleanupEntityResources(entityId: number) {
|
||||
// 清理实体相关资源
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 优先级和配置
|
||||
|
||||
```typescript
|
||||
class SystemManager {
|
||||
@EventHandler(ECSEventType.SYSTEM_ERROR, {
|
||||
priority: EventPriority.CRITICAL,
|
||||
context: this
|
||||
})
|
||||
handleSystemError(data: ISystemEventData) {
|
||||
this.logError(data);
|
||||
this.restartSystem(data.systemName);
|
||||
}
|
||||
|
||||
@AsyncEventHandler(ECSEventType.PERFORMANCE_WARNING, {
|
||||
priority: EventPriority.LOW,
|
||||
async: true
|
||||
})
|
||||
async handlePerformanceWarning(data: IPerformanceEventData) {
|
||||
await this.optimizePerformance(data);
|
||||
}
|
||||
|
||||
private logError(data: ISystemEventData) {
|
||||
// 错误日志记录
|
||||
}
|
||||
|
||||
private restartSystem(systemName: string) {
|
||||
// 重启系统
|
||||
}
|
||||
|
||||
private async optimizePerformance(data: IPerformanceEventData) {
|
||||
// 性能优化逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 事件批处理
|
||||
|
||||
```typescript
|
||||
// 设置批处理配置
|
||||
eventBus.setBatchConfig('entity:update', 100, 16); // 批量100个,延迟16ms
|
||||
|
||||
// 发射事件(会被批处理)
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
eventBus.emit('entity:update', { entityId: i, data: 'update' });
|
||||
}
|
||||
|
||||
// 手动刷新批处理队列
|
||||
eventBus.flushBatch('entity:update');
|
||||
```
|
||||
|
||||
### 事件统计和监控
|
||||
|
||||
```typescript
|
||||
// 获取单个事件统计
|
||||
const stats = eventBus.getStats('entity:created');
|
||||
console.log(`Event triggered ${stats.triggerCount} times`);
|
||||
console.log(`Average execution time: ${stats.averageExecutionTime}ms`);
|
||||
|
||||
// 获取所有事件统计
|
||||
const allStats = eventBus.getStats();
|
||||
if (allStats instanceof Map) {
|
||||
allStats.forEach((stat, eventType) => {
|
||||
console.log(`${eventType}: ${stat.triggerCount} triggers`);
|
||||
});
|
||||
}
|
||||
|
||||
// 重置统计
|
||||
eventBus.resetStats('entity:created');
|
||||
```
|
||||
|
||||
### 事件类型验证
|
||||
|
||||
```typescript
|
||||
import { EventTypeValidator } from './ECS';
|
||||
|
||||
// 检查事件类型是否有效
|
||||
if (EventTypeValidator.isValid('entity:created')) {
|
||||
eventBus.emit('entity:created', data);
|
||||
}
|
||||
|
||||
// 添加自定义事件类型
|
||||
EventTypeValidator.addCustomType('game:custom:event');
|
||||
|
||||
// 获取所有有效事件类型
|
||||
const validTypes = EventTypeValidator.getAllValidTypes();
|
||||
console.log('Valid event types:', validTypes);
|
||||
```
|
||||
|
||||
### 调试和日志
|
||||
|
||||
```typescript
|
||||
// 启用调试模式
|
||||
eventBus.setDebugMode(true);
|
||||
|
||||
// 设置最大监听器数量
|
||||
eventBus.setMaxListeners(50);
|
||||
|
||||
// 检查是否有监听器
|
||||
if (eventBus.hasListeners('entity:created')) {
|
||||
console.log('Has listeners for entity:created');
|
||||
}
|
||||
|
||||
// 获取监听器数量
|
||||
const count = eventBus.getListenerCount('entity:created');
|
||||
console.log(`${count} listeners for entity:created`);
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 事件过滤和条件监听
|
||||
|
||||
```typescript
|
||||
// 使用条件过滤减少不必要的事件处理
|
||||
eventBus.on<IEntityEventData>(ECSEventType.ENTITY_CREATED, (data) => {
|
||||
// 只处理玩家实体
|
||||
if (data.entityTag === 'player') {
|
||||
handlePlayerCreated(data);
|
||||
}
|
||||
});
|
||||
|
||||
// 更好的方式:使用具体的事件类型
|
||||
eventBus.on<IEntityEventData>('entity:player:created', handlePlayerCreated);
|
||||
```
|
||||
|
||||
### 内存管理
|
||||
|
||||
```typescript
|
||||
class EventManager {
|
||||
private listeners: string[] = [];
|
||||
|
||||
public setupListeners() {
|
||||
// 保存监听器ID以便清理
|
||||
this.listeners.push(
|
||||
eventBus.on('event1', this.handler1.bind(this)),
|
||||
eventBus.on('event2', this.handler2.bind(this))
|
||||
);
|
||||
}
|
||||
|
||||
public cleanup() {
|
||||
// 清理所有监听器
|
||||
this.listeners.forEach(id => {
|
||||
eventBus.off('event1', id);
|
||||
eventBus.off('event2', id);
|
||||
});
|
||||
this.listeners.length = 0;
|
||||
}
|
||||
|
||||
private handler1(data: any) { /* ... */ }
|
||||
private handler2(data: any) { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
### 异步事件优化
|
||||
|
||||
```typescript
|
||||
// 使用Promise.all并行处理多个异步事件
|
||||
const promises = [
|
||||
eventBus.emitAsync('save:player', playerData),
|
||||
eventBus.emitAsync('update:leaderboard', scoreData),
|
||||
eventBus.emitAsync('notify:friends', notificationData)
|
||||
];
|
||||
|
||||
await Promise.all(promises);
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 事件命名规范
|
||||
|
||||
```typescript
|
||||
// 推荐的事件命名格式:模块:对象:动作
|
||||
const EVENT_NAMES = {
|
||||
// 实体相关
|
||||
ENTITY_PLAYER_CREATED: 'entity:player:created',
|
||||
ENTITY_ENEMY_DESTROYED: 'entity:enemy:destroyed',
|
||||
|
||||
// 游戏逻辑相关
|
||||
GAME_LEVEL_COMPLETED: 'game:level:completed',
|
||||
GAME_SCORE_UPDATED: 'game:score:updated',
|
||||
|
||||
// UI相关
|
||||
UI_MENU_OPENED: 'ui:menu:opened',
|
||||
UI_BUTTON_CLICKED: 'ui:button:clicked'
|
||||
};
|
||||
```
|
||||
|
||||
### 2. 类型安全
|
||||
|
||||
```typescript
|
||||
// 定义强类型的事件数据接口
|
||||
interface GameEvents {
|
||||
'player:levelup': { playerId: number; newLevel: number; experience: number };
|
||||
'inventory:item:added': { itemId: string; quantity: number; playerId: number };
|
||||
'combat:damage:dealt': { attackerId: number; targetId: number; damage: number };
|
||||
}
|
||||
|
||||
// 创建类型安全的事件发射器
|
||||
class TypedEventBus {
|
||||
private eventBus = new EventBus();
|
||||
|
||||
emit<K extends keyof GameEvents>(eventType: K, data: GameEvents[K]) {
|
||||
this.eventBus.emit(eventType, data);
|
||||
}
|
||||
|
||||
on<K extends keyof GameEvents>(
|
||||
eventType: K,
|
||||
handler: (data: GameEvents[K]) => void
|
||||
) {
|
||||
return this.eventBus.on(eventType, handler);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
```typescript
|
||||
// 在事件处理器中添加错误处理
|
||||
eventBus.on<IEntityEventData>(ECSEventType.ENTITY_CREATED, (data) => {
|
||||
try {
|
||||
processEntityCreation(data);
|
||||
} catch (error) {
|
||||
console.error('Error processing entity creation:', error);
|
||||
// 发射错误事件
|
||||
eventBus.emit(ECSEventType.ERROR_OCCURRED, {
|
||||
timestamp: Date.now(),
|
||||
source: 'EntityCreationHandler',
|
||||
error: error.message,
|
||||
context: data
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 4. 模块化事件管理
|
||||
|
||||
```typescript
|
||||
// 为不同模块创建专门的事件管理器
|
||||
class PlayerEventManager {
|
||||
constructor(private eventBus: EventBus) {
|
||||
this.setupListeners();
|
||||
}
|
||||
|
||||
private setupListeners() {
|
||||
this.eventBus.onEntityCreated(this.onPlayerCreated.bind(this));
|
||||
this.eventBus.on('player:levelup', this.onPlayerLevelUp.bind(this));
|
||||
this.eventBus.on('player:died', this.onPlayerDied.bind(this));
|
||||
}
|
||||
|
||||
private onPlayerCreated(data: IEntityEventData) {
|
||||
if (data.entityTag === 'player') {
|
||||
// 处理玩家创建逻辑
|
||||
}
|
||||
}
|
||||
|
||||
private onPlayerLevelUp(data: any) {
|
||||
// 处理玩家升级逻辑
|
||||
}
|
||||
|
||||
private onPlayerDied(data: any) {
|
||||
// 处理玩家死亡逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 与EntityManager集成
|
||||
|
||||
```typescript
|
||||
import { EntityManager } from './ECS';
|
||||
|
||||
// EntityManager会自动设置事件总线
|
||||
const entityManager = new EntityManager();
|
||||
|
||||
// 获取事件总线实例
|
||||
const eventBus = entityManager.eventBus;
|
||||
|
||||
// 监听自动发射的ECS事件
|
||||
eventBus.onEntityCreated((data) => {
|
||||
console.log('Entity created automatically:', data);
|
||||
});
|
||||
|
||||
eventBus.onComponentAdded((data) => {
|
||||
console.log('Component added automatically:', data);
|
||||
});
|
||||
|
||||
// 创建实体时会自动发射事件
|
||||
const entity = entityManager.createEntity('Player');
|
||||
|
||||
// 添加组件时会自动发射事件
|
||||
entity.addComponent(new HealthComponent(100));
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
ECS框架的事件系统提供了:
|
||||
|
||||
- **类型安全**:完整的TypeScript类型支持
|
||||
- **高性能**:批处理、缓存和优化机制
|
||||
- **易用性**:装饰器、预定义事件类型
|
||||
- **可扩展**:自定义事件类型和验证
|
||||
- **调试友好**:详细的统计信息和调试模式
|
||||
|
||||
通过合理使用事件系统,可以实现松耦合的模块化架构,提高代码的可维护性和扩展性。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 快速入门
|
||||
|
||||
本指南将帮助您快速上手 ECS Framework,这是一个轻量级的实体组件系统框架,专为小游戏设计。
|
||||
本指南将帮助您快速上手 ECS Framework,这是一个专业级的实体组件系统框架,采用现代化架构设计,专为高性能游戏开发打造。
|
||||
|
||||
## 项目结构
|
||||
|
||||
@@ -53,8 +53,10 @@ import {
|
||||
Component,
|
||||
Scene,
|
||||
EntitySystem,
|
||||
ComponentPoolManager,
|
||||
BitMaskOptimizer
|
||||
EntityManager,
|
||||
ComponentIndexManager,
|
||||
ArchetypeSystem,
|
||||
DirtyTrackingSystem
|
||||
} from '@esengine/ecs-framework';
|
||||
```
|
||||
|
||||
@@ -64,6 +66,7 @@ import {
|
||||
class GameManager {
|
||||
private core: Core;
|
||||
private scene: Scene;
|
||||
private entityManager: EntityManager;
|
||||
|
||||
constructor() {
|
||||
// 创建核心实例
|
||||
@@ -76,24 +79,23 @@ class GameManager {
|
||||
// 设置当前场景
|
||||
Core.scene = this.scene;
|
||||
|
||||
// 初始化优化功能
|
||||
this.setupOptimizations();
|
||||
// 初始化实体管理器
|
||||
this.entityManager = new EntityManager(this.scene);
|
||||
|
||||
// 初始化性能优化
|
||||
this.setupPerformanceOptimizations();
|
||||
}
|
||||
|
||||
private setupOptimizations() {
|
||||
// 注册组件对象池
|
||||
ComponentPoolManager.getInstance().preWarmPools({
|
||||
PositionComponent: 1000,
|
||||
VelocityComponent: 1000,
|
||||
HealthComponent: 500
|
||||
});
|
||||
private setupPerformanceOptimizations() {
|
||||
// 启用组件索引(自动优化查询性能)
|
||||
// EntityManager内部已自动启用
|
||||
|
||||
// 注册位掩码优化
|
||||
const optimizer = BitMaskOptimizer.getInstance();
|
||||
optimizer.registerComponentType(PositionComponent);
|
||||
optimizer.registerComponentType(VelocityComponent);
|
||||
optimizer.registerComponentType(HealthComponent);
|
||||
optimizer.precomputeCommonMasks();
|
||||
// 可选:手动配置优化系统
|
||||
const componentIndex = this.entityManager.getComponentIndex();
|
||||
const archetypeSystem = this.entityManager.getArchetypeSystem();
|
||||
const dirtyTracking = this.entityManager.getDirtyTrackingSystem();
|
||||
|
||||
// 优化系统会自动工作,通常无需手动配置
|
||||
}
|
||||
|
||||
public update(deltaTime: number): void {
|
||||
@@ -107,6 +109,11 @@ class GameManager {
|
||||
private updateSystems(deltaTime: number): void {
|
||||
// 在这里添加您的系统更新逻辑
|
||||
}
|
||||
|
||||
// 提供实体管理器访问
|
||||
public getEntityManager(): EntityManager {
|
||||
return this.entityManager;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -201,100 +208,139 @@ class HealthComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// 注册组件到对象池
|
||||
ComponentPoolManager.getInstance().registerPool(PositionComponent, 1000);
|
||||
ComponentPoolManager.getInstance().registerPool(VelocityComponent, 1000);
|
||||
ComponentPoolManager.getInstance().registerPool(HealthComponent, 500);
|
||||
// 简单的组件定义
|
||||
// 注:框架会自动优化组件的存储和查询
|
||||
```
|
||||
|
||||
### 2. 创建实体
|
||||
## 使用 EntityManager
|
||||
|
||||
EntityManager 是框架的核心功能,提供统一的实体管理和高性能查询接口。
|
||||
|
||||
### 1. 基础用法
|
||||
|
||||
```typescript
|
||||
class GameManager {
|
||||
// ... 之前的代码 ...
|
||||
// 获取EntityManager实例(在GameManager中已创建)
|
||||
const entityManager = gameManager.getEntityManager();
|
||||
|
||||
public createPlayer(): Entity {
|
||||
const player = this.scene.createEntity("Player");
|
||||
// 创建单个实体
|
||||
const player = entityManager.createEntity("Player");
|
||||
player.addComponent(new PositionComponent(100, 100));
|
||||
player.addComponent(new VelocityComponent(50, 0));
|
||||
|
||||
// 使用对象池获取组件
|
||||
const position = ComponentPoolManager.getInstance().getComponent(PositionComponent);
|
||||
position.x = 400;
|
||||
position.y = 300;
|
||||
player.addComponent(position);
|
||||
|
||||
const velocity = ComponentPoolManager.getInstance().getComponent(VelocityComponent);
|
||||
player.addComponent(velocity);
|
||||
|
||||
const health = ComponentPoolManager.getInstance().getComponent(HealthComponent);
|
||||
health.maxHealth = 100;
|
||||
health.currentHealth = 100;
|
||||
player.addComponent(health);
|
||||
|
||||
// 设置标签和更新顺序
|
||||
player.tag = 1; // 玩家标签
|
||||
player.updateOrder = 0;
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
public createEnemies(count: number): Entity[] {
|
||||
// 使用批量创建API - 高性能
|
||||
const enemies = this.scene.createEntities(count, "Enemy");
|
||||
|
||||
// 批量配置敌人
|
||||
enemies.forEach((enemy, index) => {
|
||||
// 使用对象池获取组件
|
||||
const position = ComponentPoolManager.getInstance().getComponent(PositionComponent);
|
||||
position.x = Math.random() * 800;
|
||||
position.y = Math.random() * 600;
|
||||
enemy.addComponent(position);
|
||||
|
||||
const velocity = ComponentPoolManager.getInstance().getComponent(VelocityComponent);
|
||||
velocity.x = (Math.random() - 0.5) * 100;
|
||||
velocity.y = (Math.random() - 0.5) * 100;
|
||||
enemy.addComponent(velocity);
|
||||
|
||||
const health = ComponentPoolManager.getInstance().getComponent(HealthComponent);
|
||||
health.maxHealth = 50;
|
||||
health.currentHealth = 50;
|
||||
enemy.addComponent(health);
|
||||
|
||||
enemy.tag = 2; // 敌人标签
|
||||
enemy.updateOrder = 1;
|
||||
});
|
||||
|
||||
return enemies;
|
||||
}
|
||||
|
||||
public destroyEntity(entity: Entity): void {
|
||||
// 释放组件回对象池
|
||||
entity.components.forEach(component => {
|
||||
ComponentPoolManager.getInstance().releaseComponent(component);
|
||||
});
|
||||
|
||||
// 销毁实体
|
||||
entity.destroy();
|
||||
}
|
||||
}
|
||||
// 批量创建实体
|
||||
const enemies = entityManager.createEntities(50, "Enemy");
|
||||
enemies.forEach((enemy, index) => {
|
||||
enemy.addComponent(new PositionComponent(
|
||||
Math.random() * 800,
|
||||
Math.random() * 600
|
||||
));
|
||||
enemy.addComponent(new HealthComponent(30));
|
||||
enemy.tag = "enemy";
|
||||
});
|
||||
```
|
||||
|
||||
### 3. 创建系统
|
||||
### 2. 高性能查询
|
||||
|
||||
```typescript
|
||||
// 流式查询API - 支持复杂查询条件
|
||||
const movingEntities = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, VelocityComponent])
|
||||
.withoutTag("dead")
|
||||
.active(true)
|
||||
.execute();
|
||||
|
||||
// 快速组件查询(使用O(1)索引)
|
||||
const healthEntities = entityManager.getEntitiesWithComponent(HealthComponent);
|
||||
|
||||
// 标签查询
|
||||
const allEnemies = entityManager.getEntitiesByTag("enemy");
|
||||
|
||||
// 名称查询
|
||||
const specificEnemy = entityManager.getEntityByName("BossEnemy");
|
||||
|
||||
// 复合查询
|
||||
const livingEnemies = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, HealthComponent])
|
||||
.withTag("enemy")
|
||||
.withoutTag("dead")
|
||||
.where(entity => {
|
||||
const health = entity.getComponent(HealthComponent);
|
||||
return health && health.currentHealth > 0;
|
||||
})
|
||||
.execute();
|
||||
```
|
||||
|
||||
### 3. 批量操作
|
||||
|
||||
```typescript
|
||||
// 批量处理实体
|
||||
entityManager.forEachEntity(entity => {
|
||||
// 处理所有实体
|
||||
if (entity.tag === "bullet" && entity.position.y < 0) {
|
||||
entity.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// 批量处理特定组件的实体
|
||||
entityManager.forEachEntityWithComponent(HealthComponent, (entity, health) => {
|
||||
if (health.currentHealth <= 0) {
|
||||
entity.addTag("dead");
|
||||
entity.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 获取统计信息
|
||||
const stats = entityManager.getStatistics();
|
||||
console.log(`总实体数: ${stats.entityCount}`);
|
||||
console.log(`索引命中率: ${stats.indexHits}/${stats.totalQueries}`);
|
||||
```
|
||||
|
||||
### 4. 性能优化功能
|
||||
|
||||
```typescript
|
||||
// 获取性能优化系统
|
||||
const componentIndex = entityManager.getComponentIndex();
|
||||
const archetypeSystem = entityManager.getArchetypeSystem();
|
||||
const dirtyTracking = entityManager.getDirtyTrackingSystem();
|
||||
|
||||
// 查看性能统计
|
||||
console.log('组件索引统计:', componentIndex.getPerformanceStats());
|
||||
console.log('Archetype统计:', archetypeSystem.getStatistics());
|
||||
console.log('脏标记统计:', dirtyTracking.getPerformanceStats());
|
||||
|
||||
// 手动优化(通常自动进行)
|
||||
entityManager.optimize();
|
||||
|
||||
// 内存清理
|
||||
entityManager.cleanup();
|
||||
```
|
||||
|
||||
## 创建系统
|
||||
|
||||
系统处理具有特定组件的实体集合,实现游戏逻辑。
|
||||
|
||||
```typescript
|
||||
import { EntitySystem, Entity } from '@esengine/ecs-framework';
|
||||
|
||||
class MovementSystem extends EntitySystem {
|
||||
protected process(entities: Entity[]): void {
|
||||
// 使用高性能查询获取移动实体
|
||||
const movableEntities = this.scene.querySystem.queryTwoComponents(
|
||||
PositionComponent,
|
||||
VelocityComponent
|
||||
);
|
||||
// 使用EntityManager进行高效查询
|
||||
const entityManager = new EntityManager(this.scene);
|
||||
const movingEntities = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, VelocityComponent])
|
||||
.execute();
|
||||
|
||||
movableEntities.forEach(({ entity, component1: position, component2: velocity }) => {
|
||||
movingEntities.forEach(entity => {
|
||||
const position = entity.getComponent(PositionComponent);
|
||||
const velocity = entity.getComponent(VelocityComponent);
|
||||
|
||||
if (position && velocity) {
|
||||
// 更新位置
|
||||
position.x += velocity.x * Time.deltaTime;
|
||||
position.y += velocity.y * Time.deltaTime;
|
||||
position.x += velocity.x * 0.016; // 假设60FPS
|
||||
position.y += velocity.y * 0.016;
|
||||
|
||||
// 边界检查
|
||||
if (position.x < 0 || position.x > 800) {
|
||||
@@ -303,70 +349,37 @@ class MovementSystem extends EntitySystem {
|
||||
if (position.y < 0 || position.y > 600) {
|
||||
velocity.y = -velocity.y;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class HealthSystem extends EntitySystem {
|
||||
protected process(entities: Entity[]): void {
|
||||
const healthEntities = this.scene.querySystem.queryComponentTyped(HealthComponent);
|
||||
const deadEntities: Entity[] = [];
|
||||
const entityManager = new EntityManager(this.scene);
|
||||
|
||||
healthEntities.forEach(({ entity, component: health }) => {
|
||||
// 查找所有有生命值的实体
|
||||
entityManager.forEachEntityWithComponent(HealthComponent, (entity, health) => {
|
||||
if (health.isDead()) {
|
||||
deadEntities.push(entity);
|
||||
entity.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// 销毁死亡实体
|
||||
deadEntities.forEach(entity => {
|
||||
this.scene.removeEntity(entity);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 添加系统到场景
|
||||
gameManager.scene.addEntityProcessor(new MovementSystem());
|
||||
gameManager.scene.addEntityProcessor(new HealthSystem());
|
||||
```
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 1. 性能监控
|
||||
|
||||
```typescript
|
||||
class GameManager {
|
||||
// ... 之前的代码 ...
|
||||
|
||||
public getPerformanceStats(): void {
|
||||
const stats = this.scene.getPerformanceStats();
|
||||
console.log(`实体数量: ${stats.entityCount}`);
|
||||
console.log(`查询缓存大小: ${stats.queryCacheSize}`);
|
||||
|
||||
const poolStats = ComponentPoolManager.getInstance().getPoolStats();
|
||||
console.log('组件池统计:', poolStats);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 批量操作
|
||||
|
||||
```typescript
|
||||
// 批量创建大量实体
|
||||
const bullets = this.scene.createEntities(1000, "Bullet");
|
||||
|
||||
// 批量查询
|
||||
const enemies = this.scene.getEntitiesWithComponents([PositionComponent, HealthComponent]);
|
||||
|
||||
// 延迟缓存清理(高性能)
|
||||
bullets.forEach(bullet => {
|
||||
this.scene.addEntity(bullet, false); // 延迟清理
|
||||
});
|
||||
this.scene.querySystem.clearCache(); // 手动清理
|
||||
```
|
||||
|
||||
### 3. 事件系统
|
||||
### 事件系统
|
||||
|
||||
```typescript
|
||||
import { Core, CoreEvents } from '@esengine/ecs-framework';
|
||||
|
||||
// 监听事件
|
||||
// 监听框架事件
|
||||
Core.emitter.addObserver(CoreEvents.frameUpdated, this.onFrameUpdate, this);
|
||||
|
||||
// 发射自定义事件
|
||||
@@ -376,9 +389,23 @@ Core.emitter.emit("playerDied", { player: entity, score: 1000 });
|
||||
Core.emitter.removeObserver(CoreEvents.frameUpdated, this.onFrameUpdate);
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
### 性能监控
|
||||
|
||||
以下是一个完整的小游戏示例,展示了框架的主要功能:
|
||||
```typescript
|
||||
// 获取EntityManager性能统计
|
||||
const stats = entityManager.getStatistics();
|
||||
console.log(`总实体数: ${stats.entityCount}`);
|
||||
console.log(`索引命中率: ${stats.indexHits}/${stats.totalQueries}`);
|
||||
|
||||
// 获取各优化系统的统计
|
||||
console.log('组件索引:', entityManager.getComponentIndex().getPerformanceStats());
|
||||
console.log('Archetype:', entityManager.getArchetypeSystem().getStatistics());
|
||||
console.log('脏标记:', entityManager.getDirtyTrackingSystem().getPerformanceStats());
|
||||
```
|
||||
|
||||
## 简单示例
|
||||
|
||||
以下是一个完整的示例,展示了框架的主要功能:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
@@ -387,25 +414,14 @@ import {
|
||||
Component,
|
||||
Scene,
|
||||
EntitySystem,
|
||||
ComponentPoolManager,
|
||||
BitMaskOptimizer,
|
||||
Time
|
||||
EntityManager
|
||||
} from '@esengine/ecs-framework';
|
||||
|
||||
// 定义组件(前面已定义)
|
||||
// ... PositionComponent, VelocityComponent, HealthComponent ...
|
||||
|
||||
// 游戏事件
|
||||
enum GameEvents {
|
||||
PLAYER_DIED = 'playerDied',
|
||||
ENEMY_SPAWNED = 'enemySpawned'
|
||||
}
|
||||
|
||||
// 完整的游戏管理器
|
||||
// 游戏管理器
|
||||
class SimpleGame {
|
||||
private core: Core;
|
||||
private scene: Scene;
|
||||
private isRunning: boolean = false;
|
||||
private entityManager: EntityManager;
|
||||
|
||||
constructor() {
|
||||
this.core = Core.create(true);
|
||||
@@ -413,25 +429,8 @@ class SimpleGame {
|
||||
this.scene.name = "GameScene";
|
||||
Core.scene = this.scene;
|
||||
|
||||
this.setupOptimizations();
|
||||
this.entityManager = new EntityManager(this.scene);
|
||||
this.setupSystems();
|
||||
this.setupEvents();
|
||||
}
|
||||
|
||||
private setupOptimizations(): void {
|
||||
// 预热组件池
|
||||
ComponentPoolManager.getInstance().preWarmPools({
|
||||
PositionComponent: 2000,
|
||||
VelocityComponent: 2000,
|
||||
HealthComponent: 1000
|
||||
});
|
||||
|
||||
// 注册位掩码优化
|
||||
const optimizer = BitMaskOptimizer.getInstance();
|
||||
optimizer.registerComponentType(PositionComponent);
|
||||
optimizer.registerComponentType(VelocityComponent);
|
||||
optimizer.registerComponentType(HealthComponent);
|
||||
optimizer.precomputeCommonMasks();
|
||||
}
|
||||
|
||||
private setupSystems(): void {
|
||||
@@ -439,108 +438,50 @@ class SimpleGame {
|
||||
this.scene.addEntityProcessor(new HealthSystem());
|
||||
}
|
||||
|
||||
private setupEvents(): void {
|
||||
Core.emitter.addObserver(GameEvents.PLAYER_DIED, this.onPlayerDied, this);
|
||||
Core.emitter.addObserver(GameEvents.ENEMY_SPAWNED, this.onEnemySpawned, this);
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
this.isRunning = true;
|
||||
|
||||
// 创建游戏实体
|
||||
this.createPlayer();
|
||||
this.createEnemies(100);
|
||||
this.createEnemies(50);
|
||||
|
||||
// 启动游戏循环
|
||||
this.gameLoop();
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
this.isRunning = false;
|
||||
|
||||
// 清理组件池
|
||||
ComponentPoolManager.getInstance().clearAllPools();
|
||||
}
|
||||
|
||||
private createPlayer(): Entity {
|
||||
const player = this.scene.createEntity("Player");
|
||||
|
||||
const position = ComponentPoolManager.getInstance().getComponent(PositionComponent);
|
||||
position.x = 400;
|
||||
position.y = 300;
|
||||
player.addComponent(position);
|
||||
|
||||
const velocity = ComponentPoolManager.getInstance().getComponent(VelocityComponent);
|
||||
player.addComponent(velocity);
|
||||
|
||||
const health = ComponentPoolManager.getInstance().getComponent(HealthComponent);
|
||||
health.maxHealth = 100;
|
||||
health.currentHealth = 100;
|
||||
player.addComponent(health);
|
||||
|
||||
player.tag = 1;
|
||||
const player = this.entityManager.createEntity("Player");
|
||||
player.addComponent(new PositionComponent(400, 300));
|
||||
player.addComponent(new VelocityComponent(0, 0));
|
||||
player.addComponent(new HealthComponent(100));
|
||||
player.tag = "player";
|
||||
return player;
|
||||
}
|
||||
|
||||
private createEnemies(count: number): Entity[] {
|
||||
// 使用高性能批量创建
|
||||
const enemies = this.scene.createEntities(count, "Enemy");
|
||||
const enemies = this.entityManager.createEntities(count, "Enemy");
|
||||
|
||||
enemies.forEach((enemy, index) => {
|
||||
const position = ComponentPoolManager.getInstance().getComponent(PositionComponent);
|
||||
position.x = Math.random() * 800;
|
||||
position.y = Math.random() * 600;
|
||||
enemy.addComponent(position);
|
||||
|
||||
const velocity = ComponentPoolManager.getInstance().getComponent(VelocityComponent);
|
||||
velocity.x = (Math.random() - 0.5) * 100;
|
||||
velocity.y = (Math.random() - 0.5) * 100;
|
||||
enemy.addComponent(velocity);
|
||||
|
||||
const health = ComponentPoolManager.getInstance().getComponent(HealthComponent);
|
||||
health.maxHealth = 50;
|
||||
health.currentHealth = 50;
|
||||
enemy.addComponent(health);
|
||||
|
||||
enemy.tag = 2;
|
||||
enemy.addComponent(new PositionComponent(
|
||||
Math.random() * 800,
|
||||
Math.random() * 600
|
||||
));
|
||||
enemy.addComponent(new VelocityComponent(
|
||||
(Math.random() - 0.5) * 100,
|
||||
(Math.random() - 0.5) * 100
|
||||
));
|
||||
enemy.addComponent(new HealthComponent(50));
|
||||
enemy.tag = "enemy";
|
||||
});
|
||||
|
||||
return enemies;
|
||||
}
|
||||
|
||||
private onPlayerDied(event: any): void {
|
||||
console.log("游戏结束!玩家死亡");
|
||||
this.stop();
|
||||
}
|
||||
|
||||
private onEnemySpawned(event: any): void {
|
||||
console.log("敌人出现!");
|
||||
}
|
||||
|
||||
private update(deltaTime: number): void {
|
||||
// 更新定时器
|
||||
this.core._timerManager.update(deltaTime);
|
||||
|
||||
private gameLoop(): void {
|
||||
const update = () => {
|
||||
// 更新场景
|
||||
this.scene.update();
|
||||
}
|
||||
|
||||
private gameLoop(): void {
|
||||
let lastTime = performance.now();
|
||||
|
||||
const loop = () => {
|
||||
if (!this.isRunning) return;
|
||||
|
||||
const currentTime = performance.now();
|
||||
const deltaTime = (currentTime - lastTime) / 1000;
|
||||
lastTime = currentTime;
|
||||
|
||||
this.update(deltaTime);
|
||||
|
||||
requestAnimationFrame(loop);
|
||||
requestAnimationFrame(update);
|
||||
};
|
||||
|
||||
loop();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,28 +493,28 @@ game.start();
|
||||
## 性能优化建议
|
||||
|
||||
### 1. 大规模实体处理
|
||||
- 使用 `createEntities()` 批量创建实体
|
||||
- 启用组件对象池减少内存分配
|
||||
- 使用延迟缓存清理机制
|
||||
- 使用 `EntityManager.createEntities()` 批量创建实体
|
||||
- 利用组件索引系统进行高效查询
|
||||
- 启用Archetype系统减少查询遍历
|
||||
|
||||
### 2. 查询优化
|
||||
- 使用 `EntityManager.query()` 流式API构建复杂查询
|
||||
- 缓存频繁查询的结果
|
||||
- 使用 `BitMaskOptimizer` 优化掩码操作
|
||||
- 减少不必要的查询频率
|
||||
- 利用脏标记系统避免不必要的更新
|
||||
|
||||
### 3. 内存管理
|
||||
- 预热常用组件池
|
||||
- 及时释放不用的组件回对象池
|
||||
- 定期清理未使用的缓存
|
||||
### 3. 性能监控
|
||||
- 定期检查 `EntityManager.getStatistics()` 获取性能数据
|
||||
- 监控组件索引命中率
|
||||
- 使用框架提供的性能统计功能
|
||||
|
||||
## 下一步
|
||||
|
||||
现在您已经掌握了 ECS Framework 的基础用法,可以继续学习:
|
||||
|
||||
- [实体使用指南](entity-guide.md) - 详细了解实体的所有功能和用法
|
||||
- [EntityManager 使用指南](entity-manager-example.md) - 详细了解实体管理器的高级功能
|
||||
- [性能优化指南](performance-optimization.md) - 深入了解三大性能优化系统
|
||||
- [核心概念](core-concepts.md) - 深入了解 ECS 架构和设计原理
|
||||
- [查询系统使用指南](query-system-usage.md) - 学习高性能查询系统的详细用法
|
||||
- [性能基准](performance.md) - 了解框架的性能表现和优化建议
|
||||
|
||||
## 常见问题
|
||||
|
||||
@@ -594,14 +535,15 @@ A: 框架本身不提供输入处理,建议:
|
||||
### Q: 如何优化大规模实体性能?
|
||||
|
||||
A: 关键优化策略:
|
||||
1. 启用组件对象池:`ComponentPoolManager.getInstance().registerPool()`
|
||||
2. 使用批量操作:`scene.createEntities()`
|
||||
3. 缓存查询结果,减少查询频率
|
||||
4. 使用位掩码优化器:`BitMaskOptimizer.getInstance()`
|
||||
1. 使用 `EntityManager` 的高级查询功能
|
||||
2. 启用组件索引系统进行快速查询
|
||||
3. 利用Archetype系统减少查询遍历
|
||||
4. 使用脏标记系统避免不必要的更新
|
||||
|
||||
### Q: 组件对象池何时有效?
|
||||
### Q: EntityManager 有什么优势?
|
||||
|
||||
A: 对象池在以下情况下最有效:
|
||||
- 频繁创建和销毁相同类型的组件
|
||||
- 组件数量大于1000个
|
||||
- 游戏运行时间较长,需要避免垃圾回收压力
|
||||
A: EntityManager 提供了:
|
||||
- O(1) 复杂度的组件查询(使用索引)
|
||||
- 流式API的复杂查询构建
|
||||
- 自动的性能优化系统集成
|
||||
- 统一的实体管理接口
|
||||
497
docs/performance-optimization.md
Normal file
497
docs/performance-optimization.md
Normal file
@@ -0,0 +1,497 @@
|
||||
# 性能优化指南
|
||||
|
||||
ECS Framework 提供了多层性能优化系统,确保在各种规模的游戏中都能提供卓越的性能表现。
|
||||
|
||||
## 性能优化架构
|
||||
|
||||
### 三大核心优化系统
|
||||
|
||||
1. **组件索引系统 (ComponentIndex)** - 提供 O(1) 组件查询性能
|
||||
2. **Archetype系统** - 按组件组合分组实体,减少查询遍历
|
||||
3. **脏标记系统 (DirtyTracking)** - 细粒度变更追踪,避免不必要更新
|
||||
|
||||
这三个系统协同工作,为不同场景提供最优的性能表现。
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 核心操作性能
|
||||
|
||||
```
|
||||
实体创建: 640,000+ 个/秒
|
||||
组件查询: O(1) 复杂度(使用索引)
|
||||
内存优化: 30-50% 减少分配
|
||||
批量操作: 显著提升处理效率
|
||||
```
|
||||
|
||||
### 查询性能对比
|
||||
|
||||
| 查询类型 | 传统方式 | 使用索引 | 性能提升 |
|
||||
|----------|----------|----------|----------|
|
||||
| 单组件查询 | O(n) | O(1) | 1000x+ |
|
||||
| 多组件查询 | O(n*m) | O(k) | 100x+ |
|
||||
| 标签查询 | O(n) | O(1) | 1000x+ |
|
||||
| 复合查询 | O(n*m*k) | O(min(k1,k2)) | 500x+ |
|
||||
|
||||
*n=实体数量, m=组件种类, k=匹配实体数量*
|
||||
|
||||
## 组件索引系统
|
||||
|
||||
### 索引类型选择
|
||||
|
||||
框架提供两种索引实现:
|
||||
|
||||
#### 哈希索引 (HashComponentIndex)
|
||||
- **适用场景**: 通用查询,平衡的读写性能
|
||||
- **优势**: O(1) 查询,较低内存开销
|
||||
- **缺点**: 哈希冲突时性能下降
|
||||
|
||||
```typescript
|
||||
// 自动选择最优索引类型
|
||||
const componentIndex = entityManager.getComponentIndex();
|
||||
|
||||
// 手动配置哈希索引
|
||||
componentIndex.setIndexType(HealthComponent, 'hash');
|
||||
```
|
||||
|
||||
#### 位图索引 (BitmapComponentIndex)
|
||||
- **适用场景**: 大规模实体,频繁的组合查询
|
||||
- **优势**: 超快的 AND/OR 操作,空间压缩
|
||||
- **缺点**: 更新成本较高,内存开销随实体数量增长
|
||||
|
||||
```typescript
|
||||
// 配置位图索引用于大规模查询
|
||||
componentIndex.setIndexType(PositionComponent, 'bitmap');
|
||||
```
|
||||
|
||||
### 智能索引管理
|
||||
|
||||
ComponentIndexManager 会根据使用模式自动优化:
|
||||
|
||||
```typescript
|
||||
// 获取索引性能统计
|
||||
const stats = componentIndex.getPerformanceStats();
|
||||
console.log('索引性能:', {
|
||||
queriesPerSecond: stats.queriesPerSecond,
|
||||
hitRate: stats.hitRate,
|
||||
indexType: stats.recommendedType
|
||||
});
|
||||
|
||||
// 自动优化索引类型
|
||||
componentIndex.optimize(); // 根据使用模式切换索引类型
|
||||
```
|
||||
|
||||
## Archetype系统优化
|
||||
|
||||
### 原型分组策略
|
||||
|
||||
Archetype系统将实体按组件组合分组,实现快速批量操作:
|
||||
|
||||
```typescript
|
||||
// 获取Archetype统计
|
||||
const archetypeSystem = entityManager.getArchetypeSystem();
|
||||
const stats = archetypeSystem.getStatistics();
|
||||
|
||||
console.log('Archetype优化:', {
|
||||
totalArchetypes: stats.totalArchetypes, // 原型数量
|
||||
avgEntitiesPerArchetype: stats.averageEntitiesPerArchetype,
|
||||
queryCacheHits: stats.queryCacheHits // 缓存命中次数
|
||||
});
|
||||
```
|
||||
|
||||
### 查询缓存机制
|
||||
|
||||
```typescript
|
||||
// 启用查询缓存(默认开启)
|
||||
archetypeSystem.enableQueryCache(true);
|
||||
|
||||
// 缓存大小限制(避免内存泄漏)
|
||||
archetypeSystem.setMaxCacheSize(1000);
|
||||
|
||||
// 清理过期缓存
|
||||
archetypeSystem.cleanCache();
|
||||
```
|
||||
|
||||
### 最佳实践
|
||||
|
||||
1. **组件设计**: 避免创建过多单独的原型
|
||||
2. **批量操作**: 利用原型批量处理相同组件组合的实体
|
||||
3. **缓存管理**: 定期清理查询缓存
|
||||
|
||||
```typescript
|
||||
// ✅ 好的设计:复用组件组合
|
||||
class MovementSystem extends EntitySystem {
|
||||
process() {
|
||||
// 一次查询处理所有移动实体
|
||||
const movingEntities = this.entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, VelocityComponent])
|
||||
.execute(); // 利用Archetype快速获取
|
||||
|
||||
// 批量处理
|
||||
movingEntities.forEach(entity => {
|
||||
// 更新逻辑
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ 避免:频繁查询不同组合
|
||||
class BadSystem extends EntitySystem {
|
||||
process() {
|
||||
// 多次小查询,无法充分利用Archetype
|
||||
const players = this.queryPlayers();
|
||||
const enemies = this.queryEnemies();
|
||||
const bullets = this.queryBullets();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 脏标记系统优化
|
||||
|
||||
### 脏标记类型
|
||||
|
||||
系统提供细粒度的脏标记追踪:
|
||||
|
||||
```typescript
|
||||
enum DirtyType {
|
||||
COMPONENT_ADDED, // 组件添加
|
||||
COMPONENT_REMOVED, // 组件移除
|
||||
COMPONENT_MODIFIED, // 组件修改
|
||||
ENTITY_ENABLED, // 实体启用
|
||||
ENTITY_DISABLED, // 实体禁用
|
||||
TAG_ADDED, // 标签添加
|
||||
TAG_REMOVED // 标签移除
|
||||
}
|
||||
```
|
||||
|
||||
### 批量处理配置
|
||||
|
||||
```typescript
|
||||
const dirtyTracking = entityManager.getDirtyTrackingSystem();
|
||||
|
||||
// 配置批量处理参数
|
||||
dirtyTracking.configure({
|
||||
batchSize: 100, // 每批处理100个脏标记
|
||||
timeSliceMs: 16, // 每帧最多处理16ms
|
||||
processingInterval: 1 // 每帧处理一次
|
||||
});
|
||||
|
||||
// 监听脏标记事件
|
||||
dirtyTracking.addListener(DirtyType.COMPONENT_MODIFIED, (entity, component) => {
|
||||
// 响应组件修改
|
||||
this.invalidateRenderCache(entity);
|
||||
}, { priority: 10 });
|
||||
```
|
||||
|
||||
### 性能监控
|
||||
|
||||
```typescript
|
||||
const dirtyStats = dirtyTracking.getPerformanceStats();
|
||||
console.log('脏标记性能:', {
|
||||
totalMarks: dirtyStats.totalMarks,
|
||||
batchesProcessed: dirtyStats.batchesProcessed,
|
||||
averageBatchTime: dirtyStats.averageBatchTime,
|
||||
queueSize: dirtyStats.currentQueueSize
|
||||
});
|
||||
```
|
||||
|
||||
## 查询优化策略
|
||||
|
||||
### 查询层次选择
|
||||
|
||||
根据查询复杂度选择最优方法:
|
||||
|
||||
```typescript
|
||||
// 1. 简单查询:直接使用索引
|
||||
const healthEntities = entityManager.getEntitiesWithComponent(HealthComponent);
|
||||
|
||||
// 2. 双组件查询:使用Archetype
|
||||
const movingEntities = entityManager.getEntitiesWithComponents([
|
||||
PositionComponent,
|
||||
VelocityComponent
|
||||
]);
|
||||
|
||||
// 3. 复杂查询:组合使用
|
||||
const combatants = entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, HealthComponent]) // Archetype预筛选
|
||||
.withTag("combat") // 索引过滤
|
||||
.where(entity => { // 自定义精确过滤
|
||||
const health = entity.getComponent(HealthComponent);
|
||||
return health.currentHealth > health.maxHealth * 0.3;
|
||||
})
|
||||
.execute();
|
||||
```
|
||||
|
||||
### 查询缓存策略
|
||||
|
||||
```typescript
|
||||
class CombatSystem extends EntitySystem {
|
||||
private cachedEnemies: Entity[] = [];
|
||||
private lastEnemyCacheUpdate = 0;
|
||||
|
||||
process() {
|
||||
const currentTime = performance.now();
|
||||
|
||||
// 每200ms更新一次敌人缓存
|
||||
if (currentTime - this.lastEnemyCacheUpdate > 200) {
|
||||
this.cachedEnemies = this.entityManager
|
||||
.getEntitiesByTag("enemy");
|
||||
this.lastEnemyCacheUpdate = currentTime;
|
||||
}
|
||||
|
||||
// 使用缓存的结果
|
||||
this.processCombat(this.cachedEnemies);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 内存优化
|
||||
|
||||
### 内存使用监控
|
||||
|
||||
```typescript
|
||||
// 获取各系统内存使用情况
|
||||
const memoryStats = entityManager.getMemoryUsage();
|
||||
console.log('内存使用情况:', {
|
||||
entityIndex: memoryStats.entityIndex, // 实体索引
|
||||
componentIndex: memoryStats.componentIndex, // 组件索引
|
||||
archetype: memoryStats.archetype, // 原型系统
|
||||
dirtyTracking: memoryStats.dirtyTracking, // 脏标记
|
||||
total: memoryStats.total
|
||||
});
|
||||
```
|
||||
|
||||
### 内存清理策略
|
||||
|
||||
```typescript
|
||||
// 定期内存清理
|
||||
setInterval(() => {
|
||||
entityManager.cleanup(); // 清理无效引用
|
||||
entityManager.compact(); // 压缩数据结构
|
||||
}, 30000); // 每30秒清理一次
|
||||
|
||||
// 游戏场景切换时的深度清理
|
||||
function switchScene() {
|
||||
entityManager.destroyAllEntities();
|
||||
entityManager.cleanup();
|
||||
entityManager.compact();
|
||||
|
||||
// 重置优化系统
|
||||
entityManager.getComponentIndex().reset();
|
||||
entityManager.getArchetypeSystem().clearCache();
|
||||
entityManager.getDirtyTrackingSystem().clear();
|
||||
}
|
||||
```
|
||||
|
||||
## 实战优化案例
|
||||
|
||||
### 大规模射击游戏优化
|
||||
|
||||
```typescript
|
||||
class BulletSystem extends EntitySystem {
|
||||
private bulletPool: Entity[] = [];
|
||||
private maxBullets = 1000;
|
||||
|
||||
constructor(entityManager: EntityManager) {
|
||||
super();
|
||||
this.prewarmBulletPool();
|
||||
}
|
||||
|
||||
private prewarmBulletPool() {
|
||||
// 预创建子弹池
|
||||
this.bulletPool = this.entityManager.createEntities(
|
||||
this.maxBullets,
|
||||
"Bullet"
|
||||
);
|
||||
|
||||
// 初始化为非激活状态
|
||||
this.bulletPool.forEach(bullet => {
|
||||
bullet.enabled = false;
|
||||
bullet.addComponent(new PositionComponent());
|
||||
bullet.addComponent(new VelocityComponent());
|
||||
bullet.addComponent(new BulletComponent());
|
||||
});
|
||||
}
|
||||
|
||||
public spawnBullet(x: number, y: number, vx: number, vy: number): Entity | null {
|
||||
// 从池中获取非激活子弹(使用索引快速查询)
|
||||
const availableBullet = this.entityManager
|
||||
.query()
|
||||
.withAll([BulletComponent])
|
||||
.active(false)
|
||||
.first();
|
||||
|
||||
if (availableBullet) {
|
||||
// 重用现有子弹
|
||||
const pos = availableBullet.getComponent(PositionComponent);
|
||||
const vel = availableBullet.getComponent(VelocityComponent);
|
||||
|
||||
pos.x = x; pos.y = y;
|
||||
vel.x = vx; vel.y = vy;
|
||||
availableBullet.enabled = true;
|
||||
|
||||
return availableBullet;
|
||||
}
|
||||
|
||||
return null; // 池已满
|
||||
}
|
||||
|
||||
process() {
|
||||
// 批量处理所有激活的子弹
|
||||
this.entityManager.forEachEntityWithComponent(
|
||||
BulletComponent,
|
||||
(entity, bullet) => {
|
||||
if (!entity.enabled) return;
|
||||
|
||||
// 更新位置
|
||||
const pos = entity.getComponent(PositionComponent);
|
||||
const vel = entity.getComponent(VelocityComponent);
|
||||
|
||||
pos.x += vel.x * Time.deltaTime;
|
||||
pos.y += vel.y * Time.deltaTime;
|
||||
|
||||
// 边界检查,回收到池中
|
||||
if (pos.x < 0 || pos.x > 800 || pos.y < 0 || pos.y > 600) {
|
||||
entity.enabled = false; // 回收而不是销毁
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AI系统性能优化
|
||||
|
||||
```typescript
|
||||
class AISystem extends EntitySystem {
|
||||
private spatialGrid: SpatialGrid;
|
||||
private updateFrequency = 60; // 60Hz更新频率
|
||||
private lastUpdate = 0;
|
||||
|
||||
process() {
|
||||
const currentTime = performance.now();
|
||||
|
||||
// 控制更新频率
|
||||
if (currentTime - this.lastUpdate < 1000 / this.updateFrequency) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用空间分区优化邻居查询
|
||||
const aiEntities = this.entityManager
|
||||
.query()
|
||||
.withAll([PositionComponent, AIComponent])
|
||||
.active(true)
|
||||
.execute();
|
||||
|
||||
// 分批处理AI实体
|
||||
const batchSize = 50;
|
||||
for (let i = 0; i < aiEntities.length; i += batchSize) {
|
||||
const batch = aiEntities.slice(i, i + batchSize);
|
||||
this.processBatch(batch);
|
||||
|
||||
// 时间片控制,避免单帧卡顿
|
||||
if (performance.now() - currentTime > 10) { // 10ms时间片
|
||||
break; // 下一帧继续处理
|
||||
}
|
||||
}
|
||||
|
||||
this.lastUpdate = currentTime;
|
||||
}
|
||||
|
||||
private processBatch(entities: Entity[]) {
|
||||
entities.forEach(entity => {
|
||||
const pos = entity.getComponent(PositionComponent);
|
||||
const ai = entity.getComponent(AIComponent);
|
||||
|
||||
// 空间查询优化邻居搜索
|
||||
const neighbors = this.spatialGrid.queryRadius(pos.x, pos.y, ai.sightRange);
|
||||
|
||||
// AI决策逻辑
|
||||
ai.update(neighbors);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能监控工具
|
||||
|
||||
### 实时性能仪表板
|
||||
|
||||
```typescript
|
||||
class PerformanceDashboard {
|
||||
private stats: any = {};
|
||||
private updateInterval = 1000; // 1秒更新一次
|
||||
|
||||
constructor(private entityManager: EntityManager) {
|
||||
setInterval(() => this.updateStats(), this.updateInterval);
|
||||
}
|
||||
|
||||
private updateStats() {
|
||||
this.stats = {
|
||||
// 基础统计
|
||||
entities: this.entityManager.getStatistics(),
|
||||
|
||||
// 组件索引
|
||||
componentIndex: this.entityManager.getComponentIndex().getPerformanceStats(),
|
||||
|
||||
// Archetype系统
|
||||
archetype: this.entityManager.getArchetypeSystem().getStatistics(),
|
||||
|
||||
// 脏标记系统
|
||||
dirtyTracking: this.entityManager.getDirtyTrackingSystem().getPerformanceStats(),
|
||||
|
||||
// 内存使用
|
||||
memory: this.entityManager.getMemoryUsage(),
|
||||
|
||||
// 计算性能指标
|
||||
performance: this.calculatePerformanceMetrics()
|
||||
};
|
||||
|
||||
this.displayStats();
|
||||
}
|
||||
|
||||
private calculatePerformanceMetrics() {
|
||||
const componentStats = this.stats.componentIndex;
|
||||
const archetypeStats = this.stats.archetype;
|
||||
|
||||
return {
|
||||
queryHitRate: componentStats.hitRate,
|
||||
archetypeEfficiency: archetypeStats.averageEntitiesPerArchetype,
|
||||
memoryEfficiency: this.stats.memory.compressionRatio,
|
||||
overallPerformance: this.calculateOverallScore()
|
||||
};
|
||||
}
|
||||
|
||||
private displayStats() {
|
||||
console.log('=== ECS性能仪表板 ===');
|
||||
console.log('查询命中率:', this.stats.performance.queryHitRate.toFixed(2) + '%');
|
||||
console.log('内存使用:', (this.stats.memory.total / 1024 / 1024).toFixed(2) + 'MB');
|
||||
console.log('整体性能评分:', this.stats.performance.overallPerformance.toFixed(1) + '/10');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 优化检查清单
|
||||
|
||||
### 开发阶段
|
||||
|
||||
- [ ] 使用EntityManager而不是直接操作Scene
|
||||
- [ ] 优先使用组件查询和标签查询
|
||||
- [ ] 设计合理的组件组合,避免过度碎片化
|
||||
- [ ] 实现对象池机制减少频繁创建/销毁
|
||||
|
||||
### 运行时优化
|
||||
|
||||
- [ ] 监控查询命中率,保持在80%以上
|
||||
- [ ] 控制Archetype数量,避免过度分散
|
||||
- [ ] 配置适当的脏标记批量处理参数
|
||||
- [ ] 定期进行内存清理和数据压缩
|
||||
|
||||
### 性能监控
|
||||
|
||||
- [ ] 定期检查性能统计数据
|
||||
- [ ] 监控内存使用趋势
|
||||
- [ ] 设置性能预警阈值
|
||||
- [ ] 在不同设备上进行性能测试
|
||||
|
||||
通过系统性地应用这些优化策略,您可以构建出在各种规模下都能提供卓越性能的ECS游戏系统。
|
||||
Reference in New Issue
Block a user