空查询应该返回所有实体

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

View File

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

View File

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