@@ -14,11 +14,17 @@ export class Query {
1414 private filter : QueryFilter ;
1515 private cachedArchetypes : Archetype [ ] = [ ] ;
1616 private isDisposed = false ;
17+ /** Cached wildcard component types for faster entity filtering */
18+ private wildcardTypes : WildcardRelationId < any > [ ] ;
1719
1820 constructor ( world : World , componentTypes : EntityId < any > [ ] , filter : QueryFilter = { } ) {
1921 this . world = world ;
2022 this . componentTypes = [ ...componentTypes ] . sort ( ( a , b ) => a - b ) ;
2123 this . filter = filter ;
24+ // Pre-compute wildcard types once
25+ this . wildcardTypes = this . componentTypes . filter (
26+ ( ct ) => getDetailedIdType ( ct ) . type === "wildcard-relation" ,
27+ ) as WildcardRelationId < any > [ ] ;
2228 this . updateCache ( ) ;
2329 // Register with world for archetype updates
2430 world . _registerQuery ( this ) ;
@@ -38,48 +44,43 @@ export class Query {
3844 */
3945 getEntities ( ) : EntityId [ ] {
4046 this . ensureNotDisposed ( ) ;
41- const result : EntityId [ ] = [ ] ;
42-
43- // Check if any component types are wildcard relations
44- const hasWildcardRelations = this . componentTypes . some ( ( ct ) => {
45- const detailed = getDetailedIdType ( ct ) ;
46- return detailed . type === "wildcard-relation" ;
47- } ) ;
4847
49- // If there are wildcard relations, we need to filter entities that actually have them
50- // This is necessary for dontFragment components where an archetype can contain entities
51- // with and without the relation
52- if ( hasWildcardRelations ) {
53- for ( const archetype of this . cachedArchetypes ) {
54- for ( const entity of archetype . getEntities ( ) ) {
55- // Check if entity has all required wildcard relations
56- let hasAllRelations = true ;
57- for ( const componentType of this . componentTypes ) {
58- const detailed = getDetailedIdType ( componentType ) ;
59- if ( detailed . type === "wildcard-relation" ) {
60- // Check if entity has at least one relation matching this wildcard
61- const relations = archetype . get ( entity , componentType as WildcardRelationId < any > ) ;
62- if ( ! relations || relations . length === 0 ) {
63- hasAllRelations = false ;
64- break ;
65- }
66- }
67- }
68- if ( hasAllRelations ) {
69- result . push ( entity ) ;
70- }
71- }
72- }
73- } else {
74- // No wildcard relations, can just return all entities from matching archetypes
48+ // Fast path: no wildcard relations
49+ if ( this . wildcardTypes . length === 0 ) {
50+ const result : EntityId [ ] = [ ] ;
7551 for ( const archetype of this . cachedArchetypes ) {
7652 result . push ( ...archetype . getEntities ( ) ) ;
7753 }
54+ return result ;
7855 }
7956
57+ // Slow path: need to filter entities that actually have wildcard relations
58+ // This is necessary for dontFragment components where an archetype can contain
59+ // entities with and without the relation
60+ const result : EntityId [ ] = [ ] ;
61+ for ( const archetype of this . cachedArchetypes ) {
62+ for ( const entity of archetype . getEntities ( ) ) {
63+ if ( this . entityHasAllWildcards ( archetype , entity ) ) {
64+ result . push ( entity ) ;
65+ }
66+ }
67+ }
8068 return result ;
8169 }
8270
71+ /**
72+ * Check if entity has all required wildcard relations
73+ */
74+ private entityHasAllWildcards ( archetype : Archetype , entity : EntityId ) : boolean {
75+ for ( const wildcardType of this . wildcardTypes ) {
76+ const relations = archetype . get ( entity , wildcardType ) ;
77+ if ( ! relations || relations . length === 0 ) {
78+ return false ;
79+ }
80+ }
81+ return true ;
82+ }
83+
8384 /**
8485 * Get entities with their component data
8586 * @param componentTypes Array of component types to retrieve
@@ -188,9 +189,6 @@ export class Query {
188189 }
189190 }
190191
191- /**
192- * Dispose the query and disconnect from world
193- */
194192 /**
195193 * Request disposal of this query.
196194 * This will decrement the world's reference count for the query.
0 commit comments