空查询应该返回所有实体

This commit is contained in:
YHH
2025-10-10 11:49:06 +08:00
parent 0a0f64510f
commit bf14b59a28
3 changed files with 75 additions and 53 deletions

View File

@@ -65,8 +65,6 @@ export class ArchetypeSystem {
archetype.entities.add(entity); archetype.entities.add(entity);
this._entityToArchetype.set(entity, archetype); this._entityToArchetype.set(entity, archetype);
this.updateComponentIndexes(archetype, componentTypes, true);
} }
/** /**
@@ -119,12 +117,6 @@ export class ArchetypeSystem {
newArchetype.entities.add(entity); newArchetype.entities.add(entity);
this._entityToArchetype.set(entity, newArchetype); this._entityToArchetype.set(entity, newArchetype);
// 更新组件索引
if (currentArchetype) {
this.updateComponentIndexes(currentArchetype, currentArchetype.componentTypes, false);
}
this.updateComponentIndexes(newArchetype, newComponentTypes, true);
} }
/** /**
@@ -140,19 +132,52 @@ export class ArchetypeSystem {
let totalEntities = 0; let totalEntities = 0;
if (operation === 'AND') { if (operation === 'AND') {
// 生成查询的 BitMask if (componentTypes.length === 0) {
const queryMask = this.generateArchetypeId(componentTypes); for (const archetype of this._allArchetypes) {
// 使用 BitMask 位运算快速判断原型是否包含所有指定组件
for (const archetype of this._allArchetypes) {
if (BitMask64Utils.hasAll(archetype.id, queryMask)) {
matchingArchetypes.push(archetype); matchingArchetypes.push(archetype);
totalEntities += archetype.entities.size; totalEntities += archetype.entities.size;
} }
return { archetypes: matchingArchetypes, totalEntities };
}
if (componentTypes.length === 1) {
const archetypes = this._componentToArchetypes.get(componentTypes[0]);
if (archetypes) {
for (const archetype of archetypes) {
matchingArchetypes.push(archetype);
totalEntities += archetype.entities.size;
}
}
return { archetypes: matchingArchetypes, totalEntities };
}
let smallestSet: Set<Archetype> | undefined;
let smallestSize = Infinity;
for (const componentType of componentTypes) {
const archetypes = this._componentToArchetypes.get(componentType);
if (!archetypes || archetypes.size === 0) {
return { archetypes: [], totalEntities: 0 };
}
if (archetypes.size < smallestSize) {
smallestSize = archetypes.size;
smallestSet = archetypes;
}
}
const queryMask = this.generateArchetypeId(componentTypes);
if (smallestSet) {
for (const archetype of smallestSet) {
if (BitMask64Utils.hasAll(archetype.id, queryMask)) {
matchingArchetypes.push(archetype);
totalEntities += archetype.entities.size;
}
}
} }
} else { } else {
const foundArchetypes = new Set<Archetype>(); const foundArchetypes = new Set<Archetype>();
for (const componentType of componentTypes) { for (const componentType of componentTypes) {
const archetypes = this._componentToArchetypes.get(componentType); const archetypes = this._componentToArchetypes.get(componentType);
if (archetypes) { if (archetypes) {
@@ -161,13 +186,13 @@ export class ArchetypeSystem {
} }
} }
} }
for (const archetype of foundArchetypes) { for (const archetype of foundArchetypes) {
matchingArchetypes.push(archetype); matchingArchetypes.push(archetype);
totalEntities += archetype.entities.size; totalEntities += archetype.entities.size;
} }
} }
return { return {
archetypes: matchingArchetypes, archetypes: matchingArchetypes,
totalEntities totalEntities
@@ -252,40 +277,26 @@ export class ArchetypeSystem {
*/ */
private createArchetype(componentTypes: ComponentType[]): Archetype { private createArchetype(componentTypes: ComponentType[]): Archetype {
const id = this.generateArchetypeId(componentTypes); const id = this.generateArchetypeId(componentTypes);
const archetype: Archetype = { const archetype: Archetype = {
id, id,
componentTypes: [...componentTypes], componentTypes: [...componentTypes],
entities: new Set<Entity>() entities: new Set<Entity>()
}; };
// 存储原型ID - 原型
this._archetypes.set(id,archetype); this._archetypes.set(id,archetype);
// 更新数组
this.updateAllArchetypeArrays(); this.updateAllArchetypeArrays();
return archetype;
}
/**
* 更新组件索引
*/
private updateComponentIndexes(archetype: Archetype, componentTypes: ComponentType[], add: boolean): void {
for (const componentType of componentTypes) { for (const componentType of componentTypes) {
let archetypes = this._componentToArchetypes.get(componentType); let archetypes = this._componentToArchetypes.get(componentType);
if (!archetypes) { if (!archetypes) {
archetypes = new Set(); archetypes = new Set();
this._componentToArchetypes.set(componentType, archetypes); this._componentToArchetypes.set(componentType, archetypes);
} }
archetypes.add(archetype);
if (add) {
archetypes.add(archetype);
} else {
archetypes.delete(archetype);
if (archetypes.size === 0) {
this._componentToArchetypes.delete(componentType);
}
}
} }
return archetype;
} }
} }

View File

@@ -77,19 +77,16 @@ export class QuerySystem {
private entities: Entity[] = []; private entities: Entity[] = [];
private entityIndex: EntityIndex; private entityIndex: EntityIndex;
// 版本号,用于缓存失效
private _version = 0; private _version = 0;
// 查询缓存系统
private queryCache = new Map<string, QueryCacheEntry>(); private queryCache = new Map<string, QueryCacheEntry>();
private cacheMaxSize = 1000; private cacheMaxSize = 1000;
private cacheTimeout = 5000; // 5秒缓存过期 private cacheTimeout = 5000;
private componentMaskCache = new Map<string, BitMask64Data>(); private componentMaskCache = new Map<string, BitMask64Data>();
private archetypeSystem: ArchetypeSystem; private archetypeSystem: ArchetypeSystem;
// 性能统计
private queryStats = { private queryStats = {
totalQueries: 0, totalQueries: 0,
cacheHits: 0, cacheHits: 0,
@@ -99,6 +96,9 @@ export class QuerySystem {
dirtyChecks: 0 dirtyChecks: 0
}; };
private resultArrayPool: Entity[][] = [];
private poolMaxSize = 50;
constructor() { constructor() {
this.entityIndex = { this.entityIndex = {
byTag: new Map(), byTag: new Map(),
@@ -108,7 +108,19 @@ export class QuerySystem {
this.archetypeSystem = new ArchetypeSystem(); this.archetypeSystem = new ArchetypeSystem();
} }
private acquireResultArray(): Entity[] {
if (this.resultArrayPool.length > 0) {
return this.resultArrayPool.pop()!;
}
return [];
}
private releaseResultArray(array: Entity[]): void {
if (this.resultArrayPool.length < this.poolMaxSize) {
array.length = 0;
this.resultArrayPool.push(array);
}
}
/** /**
* 设置实体列表并重建索引 * 设置实体列表并重建索引
@@ -459,18 +471,21 @@ export class QuerySystem {
this.queryStats.archetypeHits++; this.queryStats.archetypeHits++;
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'OR'); const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'OR');
const entities: Entity[] = []; const entities = this.acquireResultArray();
for (const archetype of archetypeResult.archetypes) { for (const archetype of archetypeResult.archetypes) {
for (const entity of archetype.entities) { for (const entity of archetype.entities) {
entities.push(entity); entities.push(entity);
} }
} }
this.addToCache(cacheKey, entities); const frozenEntities = [...entities];
this.releaseResultArray(entities);
this.addToCache(cacheKey, frozenEntities);
return { return {
entities, entities: frozenEntities,
count: entities.length, count: frozenEntities.length,
executionTime: performance.now() - startTime, executionTime: performance.now() - startTime,
fromCache: false fromCache: false
}; };

View File

@@ -518,21 +518,17 @@ describe('Scene - 场景管理系统测试', () => {
// 测试查询性能 // 测试查询性能
const queryStartTime = performance.now(); const queryStartTime = performance.now();
const positionResult = scene.querySystem.queryAll(PositionComponent); const positionResult = scene.querySystem.queryAll(PositionComponent);
const velocityResult = scene.querySystem.queryAll(VelocityComponent); const velocityResult = scene.querySystem.queryAll(VelocityComponent);
const healthResult = scene.querySystem.queryAll(HealthComponent); const healthResult = scene.querySystem.queryAll(HealthComponent);
const queryTime = performance.now() - queryStartTime; const queryTime = performance.now() - queryStartTime;
expect(positionResult.entities.length).toBe(entityCount); expect(positionResult.entities.length).toBe(entityCount);
expect(velocityResult.entities.length).toBe(entityCount / 2); expect(velocityResult.entities.length).toBe(entityCount / 2);
expect(healthResult.entities.length).toBe(Math.floor(entityCount / 3) + 1); expect(healthResult.entities.length).toBe(Math.floor(entityCount / 3) + 1);
// 性能断言(这些值可能需要根据实际环境调整)
// 性能记录场景创建性能数据不设硬阈值避免CI不稳定
// 性能记录场景查询性能数据不设硬阈值避免CI不稳定
console.log(`创建${entityCount}个实体耗时: ${creationTime.toFixed(2)}ms`); console.log(`创建${entityCount}个实体耗时: ${creationTime.toFixed(2)}ms`);
console.log(`查询操作耗时: ${queryTime.toFixed(2)}ms`); console.log(`查询操作耗时: ${queryTime.toFixed(2)}ms`);
}); });