空查询应该返回所有实体
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user