diff --git a/package-lock.json b/package-lock.json index bc2f17d..0e7397b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "geotic": "4.1.6", "goodluck": "7.0.0", "harmony-ecs": "0.0.12", + "js13k-ecs": "^1.0.0", "miniplex": "^0.9.0", "perform-ecs": "0.7.8", "picoes": "1.0.0", @@ -92,6 +93,12 @@ "node": ">=14.18.1" } }, + "node_modules/js13k-ecs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/js13k-ecs/-/js13k-ecs-1.0.0.tgz", + "integrity": "sha512-RfSibZBKCcBj6WVnA/jncq17Mg1Z9RRpXUv5bCZq6sVO+p76j83ZpZNY0rBHUzoa7CnzwQh6oeiDt0Suo5IZ1w==", + "license": "MIT" + }, "node_modules/miniplex": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/miniplex/-/miniplex-0.9.0.tgz", @@ -215,6 +222,11 @@ "resolved": "https://registry.npmjs.org/harmony-ecs/-/harmony-ecs-0.0.12.tgz", "integrity": "sha512-he27c8UUVi3TeCGYxMMQ0q7L+Y5xWTiA7UZXvt2h/97pnRUle0aJtdToTKPKXmb3ulqfo8+otun+iqPxzH2CEg==" }, + "js13k-ecs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/js13k-ecs/-/js13k-ecs-1.0.0.tgz", + "integrity": "sha512-RfSibZBKCcBj6WVnA/jncq17Mg1Z9RRpXUv5bCZq6sVO+p76j83ZpZNY0rBHUzoa7CnzwQh6oeiDt0Suo5IZ1w==" + }, "miniplex": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/miniplex/-/miniplex-0.9.0.tgz", diff --git a/package.json b/package.json index 6d45aff..91ebbcf 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "geotic": "4.1.6", "goodluck": "7.0.0", "harmony-ecs": "0.0.12", + "js13k-ecs": "^1.0.0", "miniplex": "^0.9.0", "perform-ecs": "0.7.8", "picoes": "1.0.0", diff --git a/src/bench.js b/src/bench.js index 3d17ad7..ae22520 100644 --- a/src/bench.js +++ b/src/bench.js @@ -21,6 +21,7 @@ const LIBRARIES = [ { kind: OBJ, name: "picoes" }, { kind: OBJ, name: "tiny-ecs" }, { kind: OBJ, name: "uecs" }, + { kind: OBJ, name: "js13k-ecs" }, ]; const BENCHMARKS = { diff --git a/src/cases/js13k-ecs/add_remove.js b/src/cases/js13k-ecs/add_remove.js new file mode 100644 index 0000000..066bced --- /dev/null +++ b/src/cases/js13k-ecs/add_remove.js @@ -0,0 +1,41 @@ +import ecs from "js13k-ecs"; +const [registerComponents, createWorld] = ecs; + +class A {} +class B {} + +class AddB { + constructor(world) { + this.query = world.query(A); + } + + update() { + this.query.iterate((_, entity) => entity.add(new B())); + } +} + +class RemoveB { + constructor(world) { + this.query = world.query(B); + } + + update() { + this.query.iterate((_, entity) => entity.remove(B)); + } +} + +export default (count) => { + const world = createWorld(); + + registerComponents(A, B); + + for (let i = 0; i < count; i++) { + world.create().add(new A()); + } + + const pipeline = [new AddB(world), new RemoveB(world)]; + + return () => { + world.update(pipeline); + }; +}; diff --git a/src/cases/js13k-ecs/entity_cycle.js b/src/cases/js13k-ecs/entity_cycle.js new file mode 100644 index 0000000..8715721 --- /dev/null +++ b/src/cases/js13k-ecs/entity_cycle.js @@ -0,0 +1,51 @@ +import ecs from "js13k-ecs"; +const [registerComponents, createWorld] = ecs; + +class Comp { + constructor(value) { + this.value = value; + } +} + +class A extends Comp {} +class B extends Comp {} + +class SpawnB { + constructor(world) { + this.world = world; + this.query = world.query(A); + this.iterator = (a) => { + this.world.create().add(new B(a.value)); + }; + } + + update() { + this.query.iterate(this.iterator); + } +} + +class KillB { + constructor(world) { + this.query = world.query(B); + } + + update() { + this.query.iterate((_, entity) => entity.delete()); + } +} + +export default (count) => { + const world = createWorld(); + + registerComponents(A, B); + + for (let i = 0; i < count; i++) { + world.create().add(new A(i)); + } + + const pipeline = [new SpawnB(world), new KillB(world)]; + + return () => { + world.update(pipeline); + }; +}; diff --git a/src/cases/js13k-ecs/frag_iter.js b/src/cases/js13k-ecs/frag_iter.js new file mode 100644 index 0000000..0cf42ec --- /dev/null +++ b/src/cases/js13k-ecs/frag_iter.js @@ -0,0 +1,60 @@ +import ecs from "js13k-ecs"; +const [registerComponents, createWorld] = ecs; + +class Comp { + constructor(value) { + this.value = value; + } +} + +class Data extends Comp {} + +const COMPS = Array.from( + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + () => class extends Comp {}, +); + +const Z = COMPS[25]; + +const mult2 = (data) => { + data.value *= 2; +}; + +class DataSystem { + constructor(world) { + this.query = world.query(Data); + } + + update() { + this.query.iterate(mult2); + } +} + +class ZSystem { + constructor(world) { + this.query = world.query(Z); + } + + update() { + this.query.iterate(mult2); + } +} + +export default (count) => { + const world = createWorld(); + + registerComponents(...COMPS); + registerComponents(Data); + + for (let i = 0; i < count; i++) { + for (let Comp of COMPS) { + world.create().add(new Comp(0), new Data(0)); + } + } + + const pipeline = [new DataSystem(world), new ZSystem(world)]; + + return () => { + world.update(pipeline); + }; +}; diff --git a/src/cases/js13k-ecs/packed_5.js b/src/cases/js13k-ecs/packed_5.js new file mode 100644 index 0000000..8eac797 --- /dev/null +++ b/src/cases/js13k-ecs/packed_5.js @@ -0,0 +1,90 @@ +import ecs from "js13k-ecs"; +const [registerComponents, createWorld] = ecs; + +class Comp { + constructor(value) { + this.value = value; + } +} + +class A extends Comp {} +class B extends Comp {} +class C extends Comp {} +class D extends Comp {} +class E extends Comp {} + +const mult2 = (data) => { + data.value *= 2; +}; + +class ASystem { + constructor(world) { + this.query = world.query(A); + } + + update() { + this.query.iterate(mult2); + } +} + +class BSystem { + constructor(world) { + this.query = world.query(B); + } + + update() { + this.query.iterate(mult2); + } +} + +class CSystem { + constructor(world) { + this.query = world.query(C); + } + + update() { + this.query.iterate(mult2); + } +} + +class DSystem { + constructor(world) { + this.query = world.query(D); + } + + update() { + this.query.iterate(mult2); + } +} + +class ESystem { + constructor(world) { + this.query = world.query(E); + } + + update() { + this.query.iterate(mult2); + } +} + +export default (count) => { + const world = createWorld(); + + registerComponents(A, B, C, D, E); + + for (let i = 0; i < count; i++) { + world.create().add(new A(0), new B(0), new C(0), new D(0), new E(0)); + } + + const pipeline = [ + new ASystem(world), + new BSystem(world), + new CSystem(world), + new DSystem(world), + new ESystem(world), + ]; + + return () => { + world.update(pipeline); + }; +}; diff --git a/src/cases/js13k-ecs/simple_iter.js b/src/cases/js13k-ecs/simple_iter.js new file mode 100644 index 0000000..1923a03 --- /dev/null +++ b/src/cases/js13k-ecs/simple_iter.js @@ -0,0 +1,73 @@ +import ecs from "js13k-ecs"; +const [registerComponents, createWorld] = ecs; + +class Comp { + constructor(value) { + this.value = value; + } +} + +class A extends Comp {} +class B extends Comp {} +class C extends Comp {} +class D extends Comp {} +class E extends Comp {} + +const swap = ([a, b]) => { + const x = a.value; + a.value = b.value; + b.value = x; +}; + +class ABSystem { + constructor(world) { + this.query = world.query(A, B); + } + + update() { + this.query.iterate(swap); + } +} + +class CDSystem { + constructor(world) { + this.query = world.query(C, D); + } + + update() { + this.query.iterate(swap); + } +} + +class CESystem { + constructor(world) { + this.query = world.query(C, E); + } + + update() { + this.query.iterate(swap); + } +} + +export default (count) => { + const world = createWorld(); + + registerComponents(A, B, C, D, E); + + for (let i = 0; i < count; i++) { + world.create().add(new A(0), new B(1)); + world.create().add(new A(0), new B(1), new C(2)); + world.create().add(new A(0), new B(1), new C(2), new D(3)); + world.create().add(new A(0), new B(1), new C(2), new D(3), new E(4)); + } + + const pipeline = [ + new ABSystem(world), + new CDSystem(world), + new CESystem(world), + ]; + + return () => { + world.update(pipeline); + }; +};