docs: 更新项目文档 - 添加EntityManager、事件系统、性能优化使用示例和说明

This commit is contained in:
YHH
2025-06-09 13:25:10 +08:00
parent 4095f1e946
commit 40b3fe7165
5 changed files with 1824 additions and 527 deletions

427
README.md
View File

@@ -3,18 +3,17 @@
[![npm version](https://badge.fury.io/js/%40esengine%2Fecs-framework.svg)](https://badge.fury.io/js/%40esengine%2Fecs-framework)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
一个轻量级的 TypeScript ECSEntity-Component-System框架专为小游戏开发设计,适用于 Laya、Cocos 等游戏引擎
一个专业级的 TypeScript ECSEntity-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** - 让游戏开发更简单、更高效!

View 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游戏系统。

View 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类型支持
- **高性能**:批处理、缓存和优化机制
- **易用性**:装饰器、预定义事件类型
- **可扩展**:自定义事件类型和验证
- **调试友好**:详细的统计信息和调试模式
通过合理使用事件系统,可以实现松耦合的模块化架构,提高代码的可维护性和扩展性。

View File

@@ -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的复杂查询构建
- 自动的性能优化系统集成
- 统一的实体管理接口

View 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游戏系统。