11 KiB
11 KiB
EntityManager 使用指南
EntityManager 是 ECS Framework 的核心管理系统,提供统一的实体管理、高性能查询和自动优化功能。
快速开始
创建实体管理器
import { EntityManager, Scene } from '@esengine/ecs-framework';
// 通常在游戏管理器中创建
const scene = new Scene();
const entityManager = new EntityManager(scene);
基础实体操作
// 创建单个实体
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 提供多种查询方式,自动选择最优的查询策略。
基础查询
// 通过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 提供强大的流式查询构建器:
// 基础查询构建
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");
}
});
高级查询选项
// 组合条件查询
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 提供高效的批量操作方法:
// 遍历所有实体
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)性能:
// 获取组件索引统计
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系统
按组件组合分组实体,优化批量查询:
// 获取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. 脏标记系统
追踪实体变更,避免不必要的更新:
// 获取脏标记统计
const dirtyTracking = entityManager.getDirtyTrackingSystem();
const dirtyStats = dirtyTracking.getPerformanceStats();
console.log('脏标记统计:', {
totalMarks: dirtyStats.totalMarks,
batchesProcessed: dirtyStats.batchesProcessed,
listenersNotified: dirtyStats.listenersNotified
});
// 手动处理脏标记
dirtyTracking.processDirtyMarks();
实体管理器统计
获取EntityManager的综合性能数据:
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) + '%'
});
系统优化和清理
// 手动触发优化
entityManager.optimize();
// 内存清理
entityManager.cleanup();
// 压缩数据结构
entityManager.compact();
// 获取内存使用情况
const memoryStats = entityManager.getMemoryUsage();
console.log('内存使用:', {
entityIndexSize: memoryStats.entityIndex,
componentIndexSize: memoryStats.componentIndex,
archetypeSize: memoryStats.archetype
});
实际使用案例
游戏系统集成
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;
});
}
}
复杂查询示例
// 战斗系统:查找攻击范围内的敌人
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();
}
}
性能建议
查询优化
- 利用索引: 优先使用组件查询和标签查询,它们具有O(1)性能
- 减少自定义过滤:
where()条件虽然灵活,但会降低性能 - 缓存查询结果: 对于不经常变化的查询结果,考虑缓存
// ✅ 推荐:使用索引查询
const enemies = entityManager.getEntitiesByTag("enemy");
// ⚠️ 谨慎:自定义过滤
const enemies = entityManager
.query()
.where(entity => entity.name.includes("Enemy"))
.execute();
批量操作优化
// ✅ 推荐:批量创建
const bullets = entityManager.createEntities(100, "Bullet");
// ❌ 避免:循环单独创建
for (let i = 0; i < 100; i++) {
entityManager.createEntity("Bullet");
}
内存管理
// 定期清理
setInterval(() => {
entityManager.cleanup();
}, 30000); // 每30秒清理一次
// 监控性能
const stats = entityManager.getStatistics();
if (stats.indexHits / stats.totalQueries < 0.8) {
console.warn('查询命中率较低,考虑优化查询策略');
}
总结
EntityManager 提供了:
- 统一接口: 所有实体操作通过一个管理器完成
- 自动优化: 内置三个性能优化系统
- 灵活查询: 从简单的ID查找到复杂的条件查询
- 性能监控: 完整的统计和诊断信息
- 批量操作: 高效的批量处理能力
通过合理使用EntityManager,您可以构建高性能、可维护的ECS游戏系统。