Initial Commit
This commit is contained in:
103
packages/gaming/games/ecs/src/query/query.test.ts
Normal file
103
packages/gaming/games/ecs/src/query/query.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { Archetype } from "../archetype/archetype.js";
|
||||
import { BitSet } from "../bitset/bitset.js";
|
||||
import { ComponentRegistry } from "../component-registry/component-registry.js";
|
||||
import { defineComponent } from "../schema/schema.js";
|
||||
import { defineQuery, Query } from "./query.js";
|
||||
|
||||
const Position = defineComponent("Position", { x: 0 });
|
||||
const Velocity = defineComponent("Velocity", { dx: 0 });
|
||||
const Disabled = defineComponent("Disabled", { d: true });
|
||||
|
||||
function makeArch(
|
||||
registry: ComponentRegistry,
|
||||
schemas: (typeof Position)[]
|
||||
): Archetype {
|
||||
const mask = new BitSet(registry.maxComponents);
|
||||
const ids: number[] = [];
|
||||
for (const s of schemas) {
|
||||
const id = registry.getId(s);
|
||||
mask.set(id);
|
||||
ids.push(id);
|
||||
}
|
||||
ids.sort((a, b) => a - b);
|
||||
return new Archetype(mask, ids);
|
||||
}
|
||||
|
||||
describe("Query", () => {
|
||||
it("include-only matches every superset archetype", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const reg = new ComponentRegistry();
|
||||
reg.register(Position);
|
||||
reg.register(Velocity);
|
||||
const arch1 = makeArch(reg, [Position]);
|
||||
const arch2 = makeArch(reg, [Position, Velocity]);
|
||||
const arch3 = makeArch(reg, [Velocity]);
|
||||
for (const id of [10, 11]) arch1.addEntity(id, new Map());
|
||||
arch2.addEntity(20, new Map());
|
||||
arch3.addEntity(30, new Map());
|
||||
|
||||
const q = new Query(defineQuery([Position]), reg);
|
||||
const result = q.evaluate([arch1, arch2, arch3]);
|
||||
expect([...result].sort((a, b) => a - b)).toEqual([10, 11, 20]);
|
||||
});
|
||||
|
||||
it("exclude filters out archetypes whose mask intersects the exclude mask", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const reg = new ComponentRegistry();
|
||||
reg.register(Position);
|
||||
reg.register(Disabled);
|
||||
const archEnabled = makeArch(reg, [Position]);
|
||||
const archDisabled = makeArch(reg, [Position, Disabled]);
|
||||
archEnabled.addEntity(1, new Map());
|
||||
archDisabled.addEntity(2, new Map());
|
||||
|
||||
const q = new Query(defineQuery([Position], [Disabled]), reg);
|
||||
const result = q.evaluate([archEnabled, archDisabled]);
|
||||
expect([...result]).toEqual([1]);
|
||||
});
|
||||
|
||||
it("invalidate clears the cached match list and forces a re-scan", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const reg = new ComponentRegistry();
|
||||
reg.register(Position);
|
||||
reg.register(Velocity);
|
||||
const arch1 = makeArch(reg, [Position]);
|
||||
arch1.addEntity(1, new Map());
|
||||
|
||||
const archetypes: Archetype[] = [arch1];
|
||||
const q = new Query(defineQuery([Position]), reg);
|
||||
expect(q.evaluate(archetypes)).toEqual([1]);
|
||||
|
||||
const arch2 = makeArch(reg, [Position, Velocity]);
|
||||
arch2.addEntity(2, new Map());
|
||||
archetypes.push(arch2);
|
||||
|
||||
// Without invalidate, the new archetype is not reconsidered.
|
||||
expect(q.evaluate(archetypes)).toEqual([1]);
|
||||
q.invalidate();
|
||||
expect([...q.evaluate(archetypes)].sort()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it("defineQuery omits exclude when not supplied", { timeout: 5000 }, () => {
|
||||
const descriptor = defineQuery([Position]);
|
||||
expect(descriptor.exclude).toBeUndefined();
|
||||
});
|
||||
|
||||
it("defineQuery includes exclude when provided", { timeout: 5000 }, () => {
|
||||
const descriptor = defineQuery([Position], [Disabled]);
|
||||
expect(descriptor.exclude).toEqual([Disabled]);
|
||||
});
|
||||
|
||||
it("empty exclude array is treated as no exclude", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const reg = new ComponentRegistry();
|
||||
reg.register(Position);
|
||||
const q = new Query({ include: [Position], exclude: [] }, reg);
|
||||
expect(q.excludeMask).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user