From 559d77c92cfc986775a769bb77f37ca4f9c0a0f6 Mon Sep 17 00:00:00 2001 From: cha0s Date: Wed, 26 Jun 2024 07:41:07 -0500 Subject: [PATCH] refactor: queries --- app/ecs-systems/apply-control-movement.js | 2 +- app/ecs-systems/apply-forces.js | 6 ++--- app/ecs-systems/calculate-aabbs.js | 6 +++++ app/ecs-systems/follow-camera.js | 7 ++---- app/ecs-systems/reset-forces.js | 4 ++-- app/ecs-systems/run-animations.js | 2 +- app/ecs-systems/run-ticking-promises.js | 2 +- app/ecs-systems/sprite-direction.js | 11 +++++---- app/ecs-systems/update-spatial-hash.js | 6 +++++ app/ecs/ecs.test.js | 8 +++---- app/ecs/query.js | 16 +++++--------- app/ecs/query.test.js | 27 +++++++++++++++-------- app/ecs/system.js | 2 +- 13 files changed, 56 insertions(+), 43 deletions(-) diff --git a/app/ecs-systems/apply-control-movement.js b/app/ecs-systems/apply-control-movement.js index e1f8e88..e9b586b 100644 --- a/app/ecs-systems/apply-control-movement.js +++ b/app/ecs-systems/apply-control-movement.js @@ -14,7 +14,7 @@ export default class ApplyControlMovement extends System { }; } tick() { - for (const [Controlled, Forces, Speed] of this.select('default')) { + for (const {Controlled, Forces, Speed} of this.select('default')) { if (!Controlled.locked) { Forces.impulseX += Speed.speed * (Controlled.moveRight - Controlled.moveLeft); Forces.impulseY += Speed.speed * (Controlled.moveDown - Controlled.moveUp); diff --git a/app/ecs-systems/apply-forces.js b/app/ecs-systems/apply-forces.js index e86e570..2b5caaf 100644 --- a/app/ecs-systems/apply-forces.js +++ b/app/ecs-systems/apply-forces.js @@ -9,9 +9,9 @@ export default class ApplyForces extends System { } tick(elapsed) { - for (const [Position, Forces] of this.select('default')) { - Position.x += elapsed * Forces.impulseX; - Position.y += elapsed * Forces.impulseY; + for (const {Position, Forces} of this.select('default')) { + Position.x += elapsed * (Forces.impulseX + Forces.forceX); + Position.y += elapsed * (Forces.impulseY + Forces.forceY); } } diff --git a/app/ecs-systems/calculate-aabbs.js b/app/ecs-systems/calculate-aabbs.js index 953b57f..3bc4745 100644 --- a/app/ecs-systems/calculate-aabbs.js +++ b/app/ecs-systems/calculate-aabbs.js @@ -2,6 +2,12 @@ import {System} from '@/ecs/index.js'; export default class CalculateAabbs extends System { + static get priority() { + return { + after: 'ApplyForces', + }; + } + tick() { for (const {Position: {x, y}, VisibleAabb} of this.ecs.changed(['Position'])) { if (VisibleAabb) { diff --git a/app/ecs-systems/follow-camera.js b/app/ecs-systems/follow-camera.js index d8c508c..e82b370 100644 --- a/app/ecs-systems/follow-camera.js +++ b/app/ecs-systems/follow-camera.js @@ -1,8 +1,5 @@ -import {RESOLUTION} from '@/constants.js' import {System} from '@/ecs/index.js'; -const [hx, hy] = [RESOLUTION.x / 2, RESOLUTION.y / 2]; - export default class FollowCamera extends System { static queries() { @@ -19,8 +16,8 @@ export default class FollowCamera extends System { } tick(elapsed) { - for (const [, , entityId] of this.select('default')) { - this.updateCamera(elapsed * 3, this.ecs.get(entityId)); + for (const {id} of this.select('default')) { + this.updateCamera(elapsed * 3, this.ecs.get(id)); } } diff --git a/app/ecs-systems/reset-forces.js b/app/ecs-systems/reset-forces.js index a3f156d..b509826 100644 --- a/app/ecs-systems/reset-forces.js +++ b/app/ecs-systems/reset-forces.js @@ -3,7 +3,7 @@ import {System} from '@/ecs/index.js'; export default class ResetForces extends System { static get priority() { - return {phase: 'pre'}; + return {phase: 'post'}; } static queries() { @@ -13,7 +13,7 @@ export default class ResetForces extends System { } tick() { - for (const [Forces] of this.select('default')) { + for (const {Forces} of this.select('default')) { Forces.impulseX = 0; Forces.impulseY = 0; } diff --git a/app/ecs-systems/run-animations.js b/app/ecs-systems/run-animations.js index b6cd9eb..5b9faa1 100644 --- a/app/ecs-systems/run-animations.js +++ b/app/ecs-systems/run-animations.js @@ -9,7 +9,7 @@ export default class ControlMovement extends System { } tick(elapsed) { - for (const [Sprite] of this.select('default')) { + for (const {Sprite} of this.select('default')) { Sprite.elapsed += elapsed / Sprite.speed; while (Sprite.elapsed > 1) { Sprite.elapsed -= 1; diff --git a/app/ecs-systems/run-ticking-promises.js b/app/ecs-systems/run-ticking-promises.js index 64026b9..3da2676 100644 --- a/app/ecs-systems/run-ticking-promises.js +++ b/app/ecs-systems/run-ticking-promises.js @@ -15,7 +15,7 @@ export default class RunTickingPromises extends System { } tick(elapsed) { - for (const [Ticking] of this.select('default')) { + for (const {Ticking} of this.select('default')) { if (Ticking.isTicking) { Ticking.tick(elapsed); } diff --git a/app/ecs-systems/sprite-direction.js b/app/ecs-systems/sprite-direction.js index 7d7de44..f3939ac 100644 --- a/app/ecs-systems/sprite-direction.js +++ b/app/ecs-systems/sprite-direction.js @@ -9,11 +9,10 @@ export default class SpriteDirection extends System { } tick() { - for (const [Sprite, entityId] of this.select('default')) { - const entity = this.ecs.get(entityId); + for (const {Controlled, Direction, Sprite} of this.select('default')) { const parts = []; - if (entity.Controlled) { - const {locked, moveUp, moveRight, moveDown, moveLeft} = entity.Controlled; + if (Controlled) { + const {locked, moveUp, moveRight, moveDown, moveLeft} = Controlled; if (locked) { continue; } @@ -24,14 +23,14 @@ export default class SpriteDirection extends System { parts.push('idle'); } } - if (entity.Direction) { + if (Direction) { const name = { 0: 'up', 1: 'right', 2: 'down', 3: 'left', }; - parts.push(name[entity.Direction.direction]); + parts.push(name[Direction.direction]); } if (parts.length > 0) { Sprite.animation = parts.join(':'); diff --git a/app/ecs-systems/update-spatial-hash.js b/app/ecs-systems/update-spatial-hash.js index 8240b06..6bba523 100644 --- a/app/ecs-systems/update-spatial-hash.js +++ b/app/ecs-systems/update-spatial-hash.js @@ -54,6 +54,12 @@ class SpatialHash { export default class UpdateSpatialHash extends System { + static get priority() { + return { + after: 'CalculateAabbs', + }; + } + deindex(entities) { super.deindex(entities); for (const id of entities) { diff --git a/app/ecs/ecs.test.js b/app/ecs/ecs.test.js index 61e311a..2351689 100644 --- a/app/ecs/ecs.test.js +++ b/app/ecs/ecs.test.js @@ -134,10 +134,10 @@ test('ticks systems', () => { } tick(elapsed) { - for (const [position, momentum] of this.select('default')) { - position.x += momentum.x * elapsed; - position.y += momentum.y * elapsed; - position.z += momentum.z * elapsed; + for (const {Position, Momentum} of this.select('default')) { + Position.x += Momentum.x * elapsed; + Position.y += Momentum.y * elapsed; + Position.z += Momentum.z * elapsed; } } diff --git a/app/ecs/query.js b/app/ecs/query.js index a988e03..be8aa2d 100644 --- a/app/ecs/query.js +++ b/app/ecs/query.js @@ -1,18 +1,19 @@ export default class Query { $$criteria = {with: [], without: []}; - + $$ecs; $$index = new Set(); - constructor(parameters, Components) { + constructor(parameters, ecs) { + this.$$ecs = ecs; for (let i = 0; i < parameters.length; ++i) { const parameter = parameters[i]; switch (parameter.charCodeAt(0)) { case '!'.charCodeAt(0): - this.$$criteria.without.push(Components[parameter.slice(1)]); + this.$$criteria.without.push(ecs.Components[parameter.slice(1)]); break; default: - this.$$criteria.with.push(Components[parameter]); + this.$$criteria.with.push(ecs.Components[parameter]); break; } } @@ -62,7 +63,6 @@ export default class Query { select() { const it = this.$$index.values(); - const value = []; return { [Symbol.iterator]() { return this; @@ -72,11 +72,7 @@ export default class Query { if (result.done) { return {done: true, value: undefined}; } - for (let i = 0; i < this.$$criteria.with.length; ++i) { - value[i] = this.$$criteria.with[i].get(result.value); - } - value[this.$$criteria.with.length] = result.value; - return {done: false, value}; + return {done: false, value: this.$$ecs.get(result.value)}; }, }; } diff --git a/app/ecs/query.test.js b/app/ecs/query.test.js index 82dac5d..a6ad893 100644 --- a/app/ecs/query.test.js +++ b/app/ecs/query.test.js @@ -23,15 +23,24 @@ Components.A.createMany([[2], [3]]); Components.B.createMany([[1], [2]]); Components.C.createMany([[2], [4]]); +const fakeEcs = (Components) => ({ + Components, + get(id) { + return Object.fromEntries( + Object.entries(Components) + .map(([componentName, Component]) => [componentName, Component.get(id)]) + .concat([['id', id]]) + ); + }, +}); + function testQuery(parameters, expected) { - const query = new Query(parameters, Components); + const query = new Query(parameters, fakeEcs(Components)); query.reindex([1, 2, 3]); expect(query.count) .to.equal(expected.length); for (const _ of query.select()) { - expect(_.length) - .to.equal(parameters.filter((spec) => '!'.charCodeAt(0) !== spec.charCodeAt(0)).length + 1); - expect(expected.includes(_.pop())) + expect(expected.includes(_.id)) .to.equal(true); } } @@ -51,7 +60,7 @@ test('can query excluding', () => { }); test('can deindex', () => { - const query = new Query(['A'], Components); + const query = new Query(['A'], fakeEcs(Components)); query.reindex([1, 2, 3]); expect(query.count) .to.equal(2); @@ -63,7 +72,7 @@ test('can deindex', () => { test('can reindex', () => { const Test = new (wrapSpecification('Test', {a: {type: 'int32', defaultValue: 420}})); Test.createMany([[2], [3]]); - const query = new Query(['Test'], {Test}); + const query = new Query(['Test'], fakeEcs({Test})); query.reindex([2, 3]); expect(query.count) .to.equal(2); @@ -74,10 +83,10 @@ test('can reindex', () => { }); test('can select', () => { - const query = new Query(['A'], Components); + const query = new Query(['A'], fakeEcs(Components)); query.reindex([1, 2, 3]); const it = query.select(); - const result = it.next(); - expect(result.value[0].a) + const {value: {A}} = it.next(); + expect(A.a) .to.equal(420); }); diff --git a/app/ecs/system.js b/app/ecs/system.js index b4aacec..b4fa59d 100644 --- a/app/ecs/system.js +++ b/app/ecs/system.js @@ -16,7 +16,7 @@ export default class System { this.ecs = ecs; const queries = this.constructor.queries(); for (const i in queries) { - this.queries[i] = new Query(queries[i], ecs.Components); + this.queries[i] = new Query(queries[i], ecs); } this.reindex(ecs.entities); }