11 KiB
11 KiB
性能优化指南
本文档介绍ECS框架的性能优化技术和最佳实践。
目录
查询系统优化
使用高效的查询方法
// 推荐:使用标签查询(快速)
const enemies = entityManager.getEntitiesByTag(2);
// 推荐:使用组件查询
const healthEntities = entityManager.getEntitiesWithComponent(HealthComponent);
// 推荐:使用Scene的查询系统
const movingEntities = scene.querySystem.queryAll(PositionComponent, VelocityComponent);
// 谨慎:自定义条件查询(较慢)
const nearbyEnemies = entityManager
.query()
.withAll(PositionComponent)
.where(entity => {
const pos = entity.getComponent(PositionComponent);
return pos && Math.abs(pos.x - playerX) < 100;
})
.execute();
查询结果缓存
class OptimizedCombatSystem extends EntitySystem {
private cachedEnemies: Entity[] = [];
private lastCacheUpdate = 0;
private cacheInterval = 5; // 每5帧更新一次
protected process(entities: Entity[]): void {
// 缓存查询结果
if (Time.frameCount - this.lastCacheUpdate >= this.cacheInterval) {
this.cachedEnemies = this.entityManager.getEntitiesByTag(2);
this.lastCacheUpdate = Time.frameCount;
}
// 使用缓存的结果
this.cachedEnemies.forEach(enemy => {
this.processEnemy(enemy);
});
}
private processEnemy(enemy: Entity): void {
// 处理敌人逻辑
}
}
实体管理优化
批量创建实体
// 推荐:使用Scene的批量创建
function createEnemyWave(count: number): Entity[] {
const enemies = scene.createEntities(count, "Enemy");
// 批量配置组件
enemies.forEach((enemy, index) => {
enemy.addComponent(new PositionComponent(
Math.random() * 800,
Math.random() * 600
));
enemy.addComponent(new HealthComponent(100));
enemy.addComponent(new AIComponent());
enemy.tag = 2; // 敌人标签
});
return enemies;
}
// ❌ 避免:循环单独创建
function createEnemyWaveSlow(count: number): Entity[] {
const enemies: Entity[] = [];
for (let i = 0; i < count; i++) {
const enemy = entityManager.createEntity(`Enemy_${i}`);
enemy.addComponent(new PositionComponent());
enemy.addComponent(new HealthComponent());
enemies.push(enemy);
}
return enemies;
}
实体复用策略
// 使用简单的实体复用策略
class EntityReusableManager {
private inactiveEntities: Entity[] = [];
private scene: Scene;
constructor(scene: Scene) {
this.scene = scene;
}
// 预创建实体
preCreateEntities(count: number, entityName: string): void {
const entities = this.scene.createEntities(count, entityName);
entities.forEach(entity => {
entity.enabled = false; // 禁用但不销毁
this.inactiveEntities.push(entity);
});
}
// 获取可复用实体
getReusableEntity(): Entity | null {
if (this.inactiveEntities.length > 0) {
const entity = this.inactiveEntities.pop()!;
entity.enabled = true;
return entity;
}
return null;
}
// 回收实体
recycleEntity(entity: Entity): void {
entity.enabled = false;
entity.removeAllComponents();
this.inactiveEntities.push(entity);
}
}
组件设计优化
数据局部性优化
// 推荐:紧凑的数据结构
class OptimizedPositionComponent extends Component {
public x: number = 0;
public y: number = 0;
public z: number = 0;
// 避免对象分配
public setPosition(x: number, y: number, z: number = 0): void {
this.x = x;
this.y = y;
this.z = z;
}
}
// ❌ 避免:过多对象分配
class SlowPositionComponent extends Component {
public position: { x: number; y: number; z: number } = { x: 0, y: 0, z: 0 };
public velocity: { x: number; y: number; z: number } = { x: 0, y: 0, z: 0 };
public acceleration: { x: number; y: number; z: number } = { x: 0, y: 0, z: 0 };
}
组件池化
// 使用框架内置的组件池
ComponentPoolManager.getInstance().registerPool(
'BulletComponent',
() => new BulletComponent(),
(bullet) => bullet.reset(),
1000
);
// 获取组件
const bullet = ComponentPoolManager.getInstance().acquireComponent('BulletComponent');
if (bullet) {
entity.addComponent(bullet);
}
// 释放组件
ComponentPoolManager.getInstance().releaseComponent('BulletComponent', bullet);
系统设计优化
系统更新顺序优化
class OptimizedGameManager {
private scene: Scene;
constructor() {
this.scene = new Scene();
this.setupSystems();
}
private setupSystems(): void {
// 按依赖关系排序系统
this.scene.addEntityProcessor(new InputSystem()).updateOrder = 10;
this.scene.addEntityProcessor(new MovementSystem()).updateOrder = 20;
this.scene.addEntityProcessor(new CollisionSystem()).updateOrder = 30;
this.scene.addEntityProcessor(new RenderSystem()).updateOrder = 40;
this.scene.addEntityProcessor(new CleanupSystem()).updateOrder = 50;
}
}
时间分片处理
class TimeSlicedAISystem extends EntitySystem {
private aiEntities: Entity[] = [];
private currentIndex = 0;
private entitiesPerFrame = 10;
protected process(entities: Entity[]): void {
// 获取所有AI实体
if (this.aiEntities.length === 0) {
this.aiEntities = this.entityManager.getEntitiesByTag(3); // AI标签
}
// 每帧只处理部分实体
const endIndex = Math.min(
this.currentIndex + this.entitiesPerFrame,
this.aiEntities.length
);
for (let i = this.currentIndex; i < endIndex; i++) {
this.processAI(this.aiEntities[i]);
}
// 更新索引
this.currentIndex = endIndex;
if (this.currentIndex >= this.aiEntities.length) {
this.currentIndex = 0;
this.aiEntities = []; // 重新获取实体列表
}
}
private processAI(entity: Entity): void {
// AI处理逻辑
}
}
内存管理
及时清理无用实体
class CleanupSystem extends EntitySystem {
protected process(entities: Entity[]): void {
// 清理超出边界的子弹
const bullets = this.entityManager.getEntitiesByTag(4); // 子弹标签
bullets.forEach(bullet => {
const pos = bullet.getComponent(PositionComponent);
if (pos && this.isOutOfBounds(pos)) {
this.entityManager.destroyEntity(bullet);
}
});
// 清理死亡的实体
const deadEntities = this.entityManager
.query()
.withAll(HealthComponent)
.where(entity => {
const health = entity.getComponent(HealthComponent);
return health && health.currentHealth <= 0;
})
.execute();
deadEntities.forEach(entity => {
this.entityManager.destroyEntity(entity);
});
}
private isOutOfBounds(pos: PositionComponent): boolean {
return pos.x < -100 || pos.x > 900 || pos.y < -100 || pos.y > 700;
}
}
实体复用管理
class GameEntityManager {
private bulletManager: EntityReusableManager;
private effectManager: EntityReusableManager;
constructor(scene: Scene) {
this.bulletManager = new EntityReusableManager(scene);
this.effectManager = new EntityReusableManager(scene);
// 预创建实体
this.bulletManager.preCreateEntities(100, "Bullet");
this.effectManager.preCreateEntities(50, "Effect");
}
createBullet(): Entity | null {
const bullet = this.bulletManager.getReusableEntity();
if (bullet) {
bullet.addComponent(new BulletComponent());
bullet.addComponent(new PositionComponent());
bullet.addComponent(new VelocityComponent());
}
return bullet;
}
destroyBullet(bullet: Entity): void {
this.bulletManager.recycleEntity(bullet);
}
}
性能监控
基础性能统计
class PerformanceMonitor {
private scene: Scene;
private entityManager: EntityManager;
constructor(scene: Scene, entityManager: EntityManager) {
this.scene = scene;
this.entityManager = entityManager;
}
public getPerformanceReport(): any {
return {
// 实体统计
entities: {
total: this.entityManager.entityCount,
active: this.entityManager.activeEntityCount
},
// 场景统计
scene: this.scene.getStats(),
// 查询系统统计
querySystem: this.scene.querySystem.getStats(),
// 内存使用
memory: {
used: (performance as any).memory?.usedJSHeapSize || 0,
total: (performance as any).memory?.totalJSHeapSize || 0
}
};
}
public logPerformance(): void {
const report = this.getPerformanceReport();
console.log('性能报告:', report);
}
}
帧率监控
class FPSMonitor {
private frameCount = 0;
private lastTime = performance.now();
private fps = 0;
public update(): void {
this.frameCount++;
const currentTime = performance.now();
if (currentTime - this.lastTime >= 1000) {
this.fps = this.frameCount;
this.frameCount = 0;
this.lastTime = currentTime;
if (this.fps < 30) {
console.warn(`低帧率警告: ${this.fps} FPS`);
}
}
}
public getFPS(): number {
return this.fps;
}
}
最佳实践总结
查询优化
- 优先使用标签查询和组件查询
- 缓存频繁使用的查询结果
- 避免过度使用自定义条件查询
- 合理设置查询缓存更新频率
实体管理
- 使用批量创建方法
- 实现实体池化减少GC压力
- 及时清理无用实体
- 合理设置实体标签
组件设计
- 保持组件数据紧凑
- 避免在组件中分配大量对象
- 使用组件池化
- 分离数据和行为
系统设计
- 合理安排系统更新顺序
- 对重计算任务使用时间分片
- 避免在系统中进行复杂查询
- 缓存系统间的共享数据
内存管理
- 定期清理无用实体和组件
- 使用对象池减少GC
- 监控内存使用情况
- 避免内存泄漏
通过遵循这些最佳实践,可以显著提升ECS框架的性能表现。