优化querysystem系统(减少数组拷贝)

移除dirtytracksystem
This commit is contained in:
YHH
2025-09-28 09:40:36 +08:00
parent 6da1585b6b
commit 4f651eb42e
4 changed files with 157 additions and 210 deletions

View File

@@ -62,11 +62,11 @@ export class ECSFluentAPI {
} }
/** /**
* 查找实体(简化版) * 查找实体
* @param componentTypes 组件类型 * @param componentTypes 组件类型
* @returns 实体数组 * @returns 实体数组
*/ */
public find(...componentTypes: ComponentType[]): Entity[] { public find(...componentTypes: ComponentType[]): readonly Entity[] {
return this.querySystem.queryAll(...componentTypes).entities; return this.querySystem.queryAll(...componentTypes).entities;
} }

View File

@@ -8,7 +8,6 @@ import { getComponentTypeName } from '../Decorators';
import { ComponentPoolManager } from './ComponentPool'; import { ComponentPoolManager } from './ComponentPool';
import { ComponentIndexManager } from './ComponentIndex'; import { ComponentIndexManager } from './ComponentIndex';
import { ArchetypeSystem, Archetype, ArchetypeQueryResult } from './ArchetypeSystem'; import { ArchetypeSystem, Archetype, ArchetypeQueryResult } from './ArchetypeSystem';
import { DirtyTrackingSystem, DirtyFlag } from './DirtyTrackingSystem';
/** /**
* 查询条件类型 * 查询条件类型
@@ -35,7 +34,7 @@ export interface QueryCondition {
* 实体查询结果接口 * 实体查询结果接口
*/ */
export interface QueryResult { export interface QueryResult {
entities: Entity[]; entities: readonly Entity[];
count: number; count: number;
/** 查询执行时间(毫秒) */ /** 查询执行时间(毫秒) */
executionTime: number; executionTime: number;
@@ -57,9 +56,10 @@ interface EntityIndex {
* 查询缓存条目 * 查询缓存条目
*/ */
interface QueryCacheEntry { interface QueryCacheEntry {
entities: Entity[]; entities: readonly Entity[];
timestamp: number; timestamp: number;
hitCount: number; hitCount: number;
version: number;
} }
/** /**
@@ -87,7 +87,6 @@ export class QuerySystem {
private _logger = createLogger('QuerySystem'); private _logger = createLogger('QuerySystem');
private entities: Entity[] = []; private entities: Entity[] = [];
private entityIndex: EntityIndex; private entityIndex: EntityIndex;
private indexDirty = true;
// 版本号,用于缓存失效 // 版本号,用于缓存失效
private _version = 0; private _version = 0;
@@ -97,13 +96,14 @@ export class QuerySystem {
private cacheMaxSize = 1000; private cacheMaxSize = 1000;
private cacheTimeout = 5000; // 5秒缓存过期 private cacheTimeout = 5000; // 5秒缓存过期
// 优化组件 // 性能优化缓存
private componentPoolManager: ComponentPoolManager; private componentNameCache = new WeakMap<ComponentType, string>();
private cacheKeyCache = new Map<string, string>();
private componentMaskCache = new Map<string, BitMask64Data>();
// 新增性能优化系统 // 新增性能优化系统
private componentIndexManager: ComponentIndexManager; private componentIndexManager: ComponentIndexManager;
private archetypeSystem: ArchetypeSystem; private archetypeSystem: ArchetypeSystem;
private dirtyTrackingSystem: DirtyTrackingSystem;
// 性能统计 // 性能统计
private queryStats = { private queryStats = {
@@ -123,12 +123,9 @@ export class QuerySystem {
byName: new Map() byName: new Map()
}; };
// 初始化优化组件
this.componentPoolManager = ComponentPoolManager.getInstance();
// 初始化新的性能优化系统 // 初始化新的性能优化系统
this.componentIndexManager = new ComponentIndexManager(); this.componentIndexManager = new ComponentIndexManager();
this.archetypeSystem = new ArchetypeSystem(); this.archetypeSystem = new ArchetypeSystem();
this.dirtyTrackingSystem = new DirtyTrackingSystem();
} }
@@ -163,7 +160,6 @@ export class QuerySystem {
this.componentIndexManager.addEntity(entity); this.componentIndexManager.addEntity(entity);
this.archetypeSystem.addEntity(entity); this.archetypeSystem.addEntity(entity);
this.dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_ADDED);
// 只有在非延迟模式下才立即清理缓存 // 只有在非延迟模式下才立即清理缓存
@@ -246,7 +242,6 @@ export class QuerySystem {
this.componentIndexManager.removeEntity(entity); this.componentIndexManager.removeEntity(entity);
this.archetypeSystem.removeEntity(entity); this.archetypeSystem.removeEntity(entity);
this.dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_REMOVED);
this.clearQueryCache(); this.clearQueryCache();
@@ -256,55 +251,63 @@ export class QuerySystem {
} }
/** /**
* 将实体添加到各种索引中(优化版本) * 将实体添加到各种索引中
*/ */
private addEntityToIndexes(entity: Entity): void { private addEntityToIndexes(entity: Entity): void {
const mask = entity.componentMask; const mask = entity.componentMask;
// 组件掩码索引 - 优化Map操作 // 组件掩码索引
const maskKey = mask.toString(); const maskKey = mask.toString();
let maskSet = this.entityIndex.byMask.get(maskKey); const maskSet = this.entityIndex.byMask.get(maskKey) || this.createAndSetMaskIndex(maskKey);
if (!maskSet) {
maskSet = new Set();
this.entityIndex.byMask.set(maskKey, maskSet);
}
maskSet.add(entity); maskSet.add(entity);
// 组件类型索引 - 批量处理 // 组件类型索引 - 批量处理预获取所有相关的Set
const components = entity.components; const components = entity.components;
for (let i = 0; i < components.length; i++) { for (let i = 0; i < components.length; i++) {
const componentType = components[i].constructor as ComponentType; const componentType = components[i].constructor as ComponentType;
let typeSet = this.entityIndex.byComponentType.get(componentType); const typeSet = this.entityIndex.byComponentType.get(componentType) || this.createAndSetComponentIndex(componentType);
if (!typeSet) {
typeSet = new Set();
this.entityIndex.byComponentType.set(componentType, typeSet);
}
typeSet.add(entity); typeSet.add(entity);
} }
// 标签索引 - 只在有标签时处理 // 标签索引
const tag = entity.tag; const tag = entity.tag;
if (tag !== undefined) { if (tag !== undefined) {
let tagSet = this.entityIndex.byTag.get(tag); const tagSet = this.entityIndex.byTag.get(tag) || this.createAndSetTagIndex(tag);
if (!tagSet) {
tagSet = new Set();
this.entityIndex.byTag.set(tag, tagSet);
}
tagSet.add(entity); tagSet.add(entity);
} }
// 名称索引 - 只在有名称时处理 // 名称索引
const name = entity.name; const name = entity.name;
if (name) { if (name) {
let nameSet = this.entityIndex.byName.get(name); const nameSet = this.entityIndex.byName.get(name) || this.createAndSetNameIndex(name);
if (!nameSet) {
nameSet = new Set();
this.entityIndex.byName.set(name, nameSet);
}
nameSet.add(entity); nameSet.add(entity);
} }
} }
private createAndSetMaskIndex(maskKey: string): Set<Entity> {
const set = new Set<Entity>();
this.entityIndex.byMask.set(maskKey, set);
return set;
}
private createAndSetComponentIndex(componentType: ComponentType): Set<Entity> {
const set = new Set<Entity>();
this.entityIndex.byComponentType.set(componentType, set);
return set;
}
private createAndSetTagIndex(tag: number): Set<Entity> {
const set = new Set<Entity>();
this.entityIndex.byTag.set(tag, set);
return set;
}
private createAndSetNameIndex(name: string): Set<Entity> {
const set = new Set<Entity>();
this.entityIndex.byName.set(name, set);
return set;
}
/** /**
* 从各种索引中移除实体 * 从各种索引中移除实体
*/ */
@@ -377,8 +380,6 @@ export class QuerySystem {
this.componentIndexManager.addEntity(entity); this.componentIndexManager.addEntity(entity);
this.archetypeSystem.addEntity(entity); this.archetypeSystem.addEntity(entity);
} }
this.indexDirty = false;
} }
/** /**
@@ -402,7 +403,7 @@ export class QuerySystem {
this.queryStats.totalQueries++; this.queryStats.totalQueries++;
// 生成缓存键 // 生成缓存键
const cacheKey = `all:${componentTypes.map(t => getComponentTypeName(t)).sort().join(',')}`; const cacheKey = this.generateCacheKey('all', componentTypes);
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
@@ -513,7 +514,7 @@ export class QuerySystem {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this.queryStats.totalQueries++;
const cacheKey = `any:${componentTypes.map(t => getComponentTypeName(t)).sort().join(',')}`; const cacheKey = this.generateCacheKey('any', componentTypes);
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
@@ -571,7 +572,7 @@ export class QuerySystem {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this.queryStats.totalQueries++;
const cacheKey = `none:${componentTypes.map(t => getComponentTypeName(t)).sort().join(',')}`; const cacheKey = this.generateCacheKey('none', componentTypes);
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
@@ -715,7 +716,7 @@ export class QuerySystem {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this.queryStats.totalQueries++;
const cacheKey = `component:${getComponentTypeName(componentType)}`; const cacheKey = this.generateCacheKey('component', [componentType]);
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
@@ -747,12 +748,12 @@ export class QuerySystem {
/** /**
* 从缓存获取查询结果 * 从缓存获取查询结果
*/ */
private getFromCache(cacheKey: string): Entity[] | null { private getFromCache(cacheKey: string): readonly Entity[] | null {
const entry = this.queryCache.get(cacheKey); const entry = this.queryCache.get(cacheKey);
if (!entry) return null; if (!entry) return null;
// 检查缓存是否过期 // 检查缓存是否过期或版本过期
if (Date.now() - entry.timestamp > this.cacheTimeout) { if (Date.now() - entry.timestamp > this.cacheTimeout || entry.version !== this._version) {
this.queryCache.delete(cacheKey); this.queryCache.delete(cacheKey);
return null; return null;
} }
@@ -771,9 +772,10 @@ export class QuerySystem {
} }
this.queryCache.set(cacheKey, { this.queryCache.set(cacheKey, {
entities: [...entities], // 复制数组避免引用问题 entities: entities, // 直接使用引用,通过版本号控制失效
timestamp: Date.now(), timestamp: Date.now(),
hitCount: 0 hitCount: 0,
version: this._version
}); });
} }
@@ -791,12 +793,22 @@ export class QuerySystem {
// 如果还是太满,移除最少使用的条目 // 如果还是太满,移除最少使用的条目
if (this.queryCache.size >= this.cacheMaxSize) { if (this.queryCache.size >= this.cacheMaxSize) {
const entries = Array.from(this.queryCache.entries()); let minHitCount = Infinity;
entries.sort((a, b) => a[1].hitCount - b[1].hitCount); let oldestKey = '';
let oldestTimestamp = Infinity;
const toRemove = Math.floor(this.cacheMaxSize * 0.2); // 移除20% // 单次遍历找到最少使用或最旧的条目
for (let i = 0; i < toRemove && i < entries.length; i++) { for (const [key, entry] of this.queryCache.entries()) {
this.queryCache.delete(entries[i][0]); if (entry.hitCount < minHitCount ||
(entry.hitCount === minHitCount && entry.timestamp < oldestTimestamp)) {
minHitCount = entry.hitCount;
oldestKey = key;
oldestTimestamp = entry.timestamp;
}
}
if (oldestKey) {
this.queryCache.delete(oldestKey);
} }
} }
} }
@@ -806,10 +818,48 @@ export class QuerySystem {
*/ */
private clearQueryCache(): void { private clearQueryCache(): void {
this.queryCache.clear(); this.queryCache.clear();
this.cacheKeyCache.clear();
this.componentMaskCache.clear();
} }
/** /**
* 公共方法:清理查询缓存 * 高效的缓存键生成
*/
private generateCacheKey(prefix: string, componentTypes: ComponentType[]): string {
// 快速路径:单组件查询
if (componentTypes.length === 1) {
let name = this.componentNameCache.get(componentTypes[0]);
if (!name) {
name = getComponentTypeName(componentTypes[0]);
this.componentNameCache.set(componentTypes[0], name);
}
return `${prefix}:${name}`;
}
// 多组件查询:使用排序后的类型名称创建键
const sortKey = componentTypes.map(t => {
let name = this.componentNameCache.get(t);
if (!name) {
name = getComponentTypeName(t);
this.componentNameCache.set(t, name);
}
return name;
}).sort().join(',');
const fullKey = `${prefix}:${sortKey}`;
// 检查缓存的键是否已存在
let cachedKey = this.cacheKeyCache.get(fullKey);
if (!cachedKey) {
cachedKey = fullKey;
this.cacheKeyCache.set(fullKey, cachedKey);
}
return cachedKey;
}
/**
* 清理查询缓存
* *
* 用于外部调用清理缓存,通常在批量操作后使用。 * 用于外部调用清理缓存,通常在批量操作后使用。
*/ */
@@ -817,62 +867,32 @@ export class QuerySystem {
this.clearQueryCache(); this.clearQueryCache();
} }
/**
* 批量更新实体组件
*
* 对大量实体进行批量组件更新操作。
*
* @param updates 更新操作列表包含实体ID和新的组件掩码
*
* @example
* ```typescript
* // 批量更新实体的组件配置
* const updates = [
* { entityId: 1, componentMask: BigInt(0b1011) },
* { entityId: 2, componentMask: BigInt(0b1101) }
* ];
* querySystem.batchUpdateComponents(updates);
* ```
*/
public batchUpdateComponents(updates: Array<{ entityId: number, componentMask: bigint }>): void {
// 批量处理更新,先从索引中移除,再重新添加
const entitiesToUpdate: Entity[] = [];
for (const update of updates) {
const entity = this.entities.find(e => e.id === update.entityId);
if (entity) {
// 先从所有索引中移除
this.removeEntityFromIndexes(entity);
entitiesToUpdate.push(entity);
}
}
// 重新添加到索引中(此时实体的组件掩码已经更新)
for (const entity of entitiesToUpdate) {
this.addEntityToIndexes(entity);
}
// 标记脏实体进行处理
for (const entity of entitiesToUpdate) {
this.dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_MODIFIED, []);
}
// 批量更新后清除缓存
this.clearQueryCache();
}
/** /**
* 创建组件掩码 * 创建组件掩码
* *
* 根据组件类型列表生成对应的位掩码。 * 根据组件类型列表生成对应的位掩码。
* 使用位掩码优化器进行缓存和预计算。 * 使用缓存避免重复计算。
* *
* @param componentTypes 组件类型列表 * @param componentTypes 组件类型列表
* @returns 生成的位掩码 * @returns 生成的位掩码
*/ */
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data { private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
// 生成缓存键
const cacheKey = componentTypes.map(t => {
let name = this.componentNameCache.get(t);
if (!name) {
name = getComponentTypeName(t);
this.componentNameCache.set(t, name);
}
return name;
}).sort().join(',');
// 检查缓存
const cached = this.componentMaskCache.get(cacheKey);
if (cached) {
return cached;
}
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
let hasValidComponents = false; let hasValidComponents = false;
@@ -888,9 +908,11 @@ export class QuerySystem {
// 如果没有有效的组件类型,返回一个不可能匹配的掩码 // 如果没有有效的组件类型,返回一个不可能匹配的掩码
if (!hasValidComponents) { if (!hasValidComponents) {
return { lo: 0xFFFFFFFF, hi: 0xFFFFFFFF }; // 所有位都是1不可能与任何实体匹配 mask = { lo: 0xFFFFFFFF, hi: 0xFFFFFFFF };
} }
// 缓存结果
this.componentMaskCache.set(cacheKey, mask);
return mask; return mask;
} }
@@ -904,8 +926,8 @@ export class QuerySystem {
/** /**
* 获取所有实体 * 获取所有实体
*/ */
public getAllEntities(): Entity[] { public getAllEntities(): readonly Entity[] {
return [...this.entities]; return this.entities;
} }
/** /**
@@ -936,7 +958,6 @@ export class QuerySystem {
optimizationStats: { optimizationStats: {
componentIndex: any; componentIndex: any;
archetypeSystem: any; archetypeSystem: any;
dirtyTracking: any;
}; };
cacheStats: { cacheStats: {
size: number; size: number;
@@ -962,8 +983,7 @@ export class QuerySystem {
id: a.id, id: a.id,
componentTypes: a.componentTypes.map(t => getComponentTypeName(t)), componentTypes: a.componentTypes.map(t => getComponentTypeName(t)),
entityCount: a.entities.length entityCount: a.entities.length
})), }))
dirtyTracking: this.dirtyTrackingSystem.getStats()
}, },
cacheStats: { cacheStats: {
size: this.queryCache.size, size: this.queryCache.size,
@@ -973,54 +993,6 @@ export class QuerySystem {
}; };
} }
/**
* 配置脏标记系统
*
* @param batchSize 批处理大小
* @param maxProcessingTime 最大处理时间
*/
public configureDirtyTracking(batchSize: number, maxProcessingTime: number): void {
this.dirtyTrackingSystem.configureBatchProcessing(batchSize, maxProcessingTime);
}
/**
* 手动触发性能优化
*/
public optimizePerformance(): void {
this.dirtyTrackingSystem.processDirtyEntities();
this.cleanupCache();
const stats = this.componentIndexManager.getStats();
// 基于SparseSet的索引已自动优化无需手动切换索引类型
}
/**
* 开始新的帧
*/
public beginFrame(): void {
this.dirtyTrackingSystem.beginFrame();
}
/**
* 结束当前帧
*/
public endFrame(): void {
this.dirtyTrackingSystem.endFrame();
}
/**
* 标记实体组件已修改(用于脏标记追踪)
*
* @param entity 修改的实体
* @param componentTypes 修改的组件类型
*/
public markEntityDirty(entity: Entity, componentTypes: ComponentType[]): void {
this.queryStats.dirtyChecks++;
this.dirtyTrackingSystem.markDirty(entity, DirtyFlag.COMPONENT_MODIFIED, componentTypes);
this.clearQueryCache();
}
/** /**
* 获取实体所属的原型信息 * 获取实体所属的原型信息
* *

View File

@@ -30,7 +30,7 @@ interface EventListenerRecord {
* super(Transform, Velocity); * super(Transform, Velocity);
* } * }
* *
* protected process(entities: Entity[]): void { * protected process(entities: readonly Entity[]): void {
* for (const entity of entities) { * for (const entity of entities) {
* const transform = entity.getComponent(Transform); * const transform = entity.getComponent(Transform);
* const velocity = entity.getComponent(Velocity); * const velocity = entity.getComponent(Velocity);
@@ -61,8 +61,8 @@ export abstract class EntitySystem implements ISystemBase {
* 统一的实体缓存管理器 * 统一的实体缓存管理器
*/ */
private _entityCache: { private _entityCache: {
frame: Entity[] | null; frame: readonly Entity[] | null;
persistent: Entity[] | null; persistent: readonly Entity[] | null;
tracked: Set<Entity>; tracked: Set<Entity>;
invalidate(): void; invalidate(): void;
clearFrame(): void; clearFrame(): void;
@@ -245,14 +245,14 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 查询匹配的实体 * 查询匹配的实体
*/ */
private queryEntities(): Entity[] { private queryEntities(): readonly Entity[] {
if (!this.scene?.querySystem || !this._matcher) { if (!this.scene?.querySystem || !this._matcher) {
return []; return [];
} }
const condition = this._matcher.getCondition(); const condition = this._matcher.getCondition();
const querySystem = this.scene.querySystem; const querySystem = this.scene.querySystem;
let currentEntities: Entity[] = []; let currentEntities: readonly Entity[] = [];
// 空条件返回所有实体 // 空条件返回所有实体
if (this._matcher.isEmpty()) { if (this._matcher.isEmpty()) {
@@ -289,7 +289,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 执行单一条件查询 * 执行单一条件查询
*/ */
private executeSingleConditionQuery(condition: any, querySystem: any): Entity[] { private executeSingleConditionQuery(condition: any, querySystem: any): readonly Entity[] {
// 按标签查询 // 按标签查询
if (condition.tag !== undefined) { if (condition.tag !== undefined) {
return querySystem.queryByTag(condition.tag).entities; return querySystem.queryByTag(condition.tag).entities;
@@ -324,7 +324,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 执行复合查询 * 执行复合查询
*/ */
private executeComplexQueryWithIdSets(condition: any, querySystem: QuerySystem): Entity[] { private executeComplexQueryWithIdSets(condition: any, querySystem: QuerySystem): readonly Entity[] {
let resultIds: Set<number> | null = null; let resultIds: Set<number> | null = null;
// 1. 应用标签条件作为基础集合 // 1. 应用标签条件作为基础集合
@@ -374,7 +374,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 提取实体ID集合 * 提取实体ID集合
*/ */
private extractEntityIds(entities: Entity[]): Set<number> { private extractEntityIds(entities: readonly Entity[]): Set<number> {
const len = entities.length; const len = entities.length;
const idSet = new Set<number>(); const idSet = new Set<number>();
@@ -427,7 +427,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 获取或构建实体ID映射 * 获取或构建实体ID映射
*/ */
private getEntityIdMap(allEntities: Entity[]): Map<number, Entity> { private getEntityIdMap(allEntities: readonly Entity[]): Map<number, Entity> {
const currentVersion = this.scene?.querySystem?.version ?? 0; const currentVersion = this.scene?.querySystem?.version ?? 0;
if (this._entityIdMap !== null && if (this._entityIdMap !== null &&
this._entityIdMapVersion === currentVersion) { this._entityIdMapVersion === currentVersion) {
@@ -440,7 +440,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 重建实体ID映射 * 重建实体ID映射
*/ */
private rebuildEntityIdMap(allEntities: Entity[], version: number): Map<number, Entity> { private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
let entityMap = this._entityIdMap; let entityMap = this._entityIdMap;
if (!entityMap) { if (!entityMap) {
@@ -465,7 +465,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 从ID集合构建Entity数组 * 从ID集合构建Entity数组
*/ */
private idSetToEntityArray(idSet: Set<number>, allEntities: Entity[]): Entity[] { private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
const entityMap = this.getEntityIdMap(allEntities); const entityMap = this.getEntityIdMap(allEntities);
const size = idSet.size; const size = idSet.size;
@@ -492,7 +492,7 @@ export abstract class EntitySystem implements ISystemBase {
* *
* 使用基于ID集合的单次扫描算法进行复杂查询 * 使用基于ID集合的单次扫描算法进行复杂查询
*/ */
private executeComplexQuery(condition: any, querySystem: QuerySystem): Entity[] { private executeComplexQuery(condition: any, querySystem: QuerySystem): readonly Entity[] {
return this.executeComplexQueryWithIdSets(condition, querySystem); return this.executeComplexQueryWithIdSets(condition, querySystem);
} }
@@ -559,7 +559,7 @@ export abstract class EntitySystem implements ISystemBase {
* *
* @param entities 要处理的实体列表 * @param entities 要处理的实体列表
*/ */
protected process(entities: Entity[]): void { protected process(entities: readonly Entity[]): void {
// 子类必须实现此方法 // 子类必须实现此方法
} }
@@ -570,7 +570,7 @@ export abstract class EntitySystem implements ISystemBase {
* *
* @param entities 要处理的实体列表 * @param entities 要处理的实体列表
*/ */
protected lateProcess(_entities: Entity[]): void { protected lateProcess(_entities: readonly Entity[]): void {
// 子类可以重写此方法 // 子类可以重写此方法
} }
@@ -636,7 +636,7 @@ export abstract class EntitySystem implements ISystemBase {
/** /**
* 更新实体跟踪,检查新增和移除的实体 * 更新实体跟踪,检查新增和移除的实体
*/ */
private updateEntityTracking(currentEntities: Entity[]): void { private updateEntityTracking(currentEntities: readonly Entity[]): void {
const currentSet = new Set(currentEntities); const currentSet = new Set(currentEntities);
let hasChanged = false; let hasChanged = false;

View File

@@ -538,7 +538,7 @@ describe('QuerySystem - 查询系统测试', () => {
// 修改查询结果不应该影响原始数据 // 修改查询结果不应该影响原始数据
const originalLength = result.entities.length; const originalLength = result.entities.length;
result.entities.push(entities[2]); // 尝试修改结果 // readonly 数组不可修改,这是预期的行为
const newResult = querySystem.queryAll(PositionComponent); const newResult = querySystem.queryAll(PositionComponent);
expect(newResult.entities.length).toBe(originalLength); expect(newResult.entities.length).toBe(originalLength);
@@ -819,48 +819,23 @@ describe('QuerySystem - 查询系统测试', () => {
expect(stats.entityCount).toBe(12); expect(stats.entityCount).toBe(12);
}); });
test('应该能够批量更新组件', () => { test('应该能够清理查询缓存', () => {
entities[0].addComponent(new PositionComponent(10, 20)); // 先进行一次查询建立缓存
entities[1].addComponent(new VelocityComponent(1, 1)); querySystem.queryAll(PositionComponent);
const updates = [
{ entityId: entities[0].id, componentMask: BigInt(0b1011) },
{ entityId: entities[1].id, componentMask: BigInt(0b1101) }
];
expect(() => { expect(() => {
querySystem.batchUpdateComponents(updates); querySystem.clearCache();
}).not.toThrow();
});
test('应该能够标记实体为脏', () => {
entities[0].addComponent(new PositionComponent(10, 20));
expect(() => {
querySystem.markEntityDirty(entities[0], [PositionComponent]);
}).not.toThrow(); }).not.toThrow();
}); });
}); });
describe('性能优化和配置', () => { describe('性能优化和配置', () => {
test('应该能够手动触发性能优化', () => { test('应该能够配置查询缓存', () => {
expect(() => { expect(() => {
querySystem.optimizePerformance(); querySystem.clearCache();
}).not.toThrow(); }).not.toThrow();
}); });
test('应该能够配置脏标记系统', () => {
expect(() => {
querySystem.configureDirtyTracking(10, 16);
}).not.toThrow();
});
test('应该能够管理帧生命周期', () => {
expect(() => {
querySystem.beginFrame();
querySystem.endFrame();
}).not.toThrow();
});
test('应该能够获取实体的原型信息', () => { test('应该能够获取实体的原型信息', () => {
entities[0].addComponent(new PositionComponent(10, 20)); entities[0].addComponent(new PositionComponent(10, 20));