refactor query into yielding api

This commit is contained in:
Matthieu Jolimaitre 2024-04-10 02:45:34 +02:00
parent 6bf8f60a45
commit 976a99baa1
5 changed files with 70 additions and 54 deletions

View file

@ -60,11 +60,11 @@ export class Engine {
}
}
*query_all(query: Query) {
*query_all<O extends QueryRes>(query: Query<O>) {
yield* query.run(this.entities.values());
}
query_one(query: Query) {
query_one<O extends QueryRes>(query: Query<O>) {
return first(this.query_all(query));
}
@ -85,41 +85,52 @@ export class Engine {
}
}
export class Query {
private test;
type QueryRes<T = unknown> = readonly T[];
export class Query<O extends QueryRes> {
extractor;
constructor(test: (entity: Entity) => boolean) {
this.test = test;
}
and(query: Query) {
return new Query((entity) => this.test(entity) && query.test(entity));
}
static with(...components: Constructible[]) {
return new Query((entity) => {
for (const comp of components) if (!entity.components.has(comp)) return false;
return true;
});
}
with(...components: Constructible[]) {
return this.and(Query.with(...components));
}
static filter<I>(component: Constructible<I>, filter: (comp: I, entity: Entity) => boolean) {
return new Query((entity) => {
const comp = entity.get(component);
if (comp === null) return false;
return filter(comp, entity);
});
}
filter<I>(component: Constructible<I>, filter: (comp: I, entity: Entity) => boolean) {
return this.and(Query.filter(component, filter));
constructor(extractor: (entity: Entity) => O | null) {
this.extractor = extractor;
}
*run(entities: Iterable<Entity>) {
for (const entity of entities) if (this.test(entity)) yield entity;
for (const entity of entities) {
const extracted = this.extractor(entity);
if (extracted !== null) yield extracted;
}
}
and<Q extends QueryRes>(other: Query<Q>) {
const this_extractor = this.extractor;
return new Query((entity) => {
const this_extracted = this_extractor(entity);
if (this_extracted === null) return null;
const other_extracted = other.extractor(entity);
if (other_extracted === null) return null;
return [...this_extracted, ...other_extracted] as const;
});
}
static with<I>(comp: Constructible<I>) {
function extract(entity: Entity) {
const extracted = entity.get(comp);
if (extracted === null) return null;
return [extracted] as const;
}
return new Query(extract);
}
with<I>(comp: Constructible<I>) {
return this.and(Query.with(comp));
}
filter(predicate: (comps: O) => boolean) {
const this_extract = this.extractor;
return new Query((entity) => {
const extracted = this_extract(entity);
if (extracted === null) return null;
if (predicate(extracted)) return extracted;
else return null;
});
}
}