diff --git a/packages/ecs/src/component.js b/packages/ecs/src/component.js index 2b5ff02..0013927 100644 --- a/packages/ecs/src/component.js +++ b/packages/ecs/src/component.js @@ -51,7 +51,7 @@ class BaseComponent { return this.$$dirty; } - set dirty(dirty) { + setDirty(dirty) { this.$$dirty = dirty; } @@ -84,9 +84,9 @@ class FlatComponent extends BaseComponent { // eslint-disable-next-line no-param-reassign count -= results.length; if (count > 0) { - const required = (this.caret + count) * this.schema.width; + const required = (this.caret + count) * this.constructor.width; if (required > this.data.byteLength) { - const chunkWidth = this.chunkSize * this.schema.width; + const chunkWidth = this.chunkSize * this.constructor.width; const remainder = required % chunkWidth; const extra = 0 === remainder ? 0 : chunkWidth - remainder; const size = required + extra; @@ -111,7 +111,7 @@ class FlatComponent extends BaseComponent { const window = new this.Window(this.data, this); for (let i = 0; i < this.caret; ++i) { window.dirty = false; - window.cursor += this.schema.width; + window.cursor += this.constructor.width; } this.dirty = false; } @@ -134,7 +134,8 @@ class FlatComponent extends BaseComponent { entity = entries[i]; } this.map[entity] = allocated[i]; - window.cursor = allocated[i] * this.schema.width; + window.cursor = allocated[i] * this.constructor.width; + window.entity = entity; for (const [i] of this.schema) { if (i in values) { window[i] = values[i]; @@ -155,7 +156,7 @@ class FlatComponent extends BaseComponent { this.Window = this.makeWindowClass(); } const window = new this.Window(this.data, this); - window.cursor = this.map[entity] * this.schema.width; + window.cursor = this.map[entity] * this.constructor.width; return window; } @@ -169,7 +170,7 @@ class FlatComponent extends BaseComponent { if (!this.window) { this.window = new this.Window(this.data, this); } - this.window.cursor = this.map[entity] * this.schema.width; + this.window.cursor = this.map[entity] * this.constructor.width; return this.window; } @@ -194,18 +195,23 @@ class FlatComponent extends BaseComponent { } let offset = 0; const properties = {}; + const {width} = this.constructor; const get = (type) => ( `return this.view.get${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, true);` ); const set = (type) => [ - 'this.parent.dirty = true;', + `this.parent.setDirty(1, this.view.getBigUint64(this.cursor + ${width - 9}, true));`, `this.view.set${Schema.viewMethodFromType(type)}(this.cursor + ${offset}, v, true);`, - `this.view.setUint8(this.cursor + ${this.schema.width - 1}, 1, true);`, + `this.view.setUint8(this.cursor + ${width - 1}, 1, true);`, ].join(''); /* eslint-disable no-new-func */ properties.dirty = { - get: new Function('', `return !!this.view.getUint8(this.cursor + ${this.schema.width - 1}, true);`), - set: new Function('v', `this.view.setUint8(this.cursor + ${this.schema.width - 1}, v ? 1 : 0, true);`), + get: new Function('', `return !!this.view.getUint8(this.cursor + ${width - 1}, true);`), + set: new Function('v', `this.view.setUint8(this.cursor + ${width - 1}, v ? 1 : 0, true);`), + }; + properties.entity = { + get: new Function('', `return this.view.getBigUint64(this.cursor + ${width - 9}, true);`), + set: new Function('v', `this.view.setBigUint64(this.cursor + ${width - 9}, v ? 1 : 0, true);`), }; for (const [i, spec] of this.schema) { const {type} = spec; @@ -229,7 +235,7 @@ class ArbitraryComponent extends BaseComponent { allocateMany(count) { if (!this.Instance) { - this.Instance = this.constructor.instanceFromSchema(this.schema); + this.Instance = this.instanceFromSchema(); } const results = super.allocateMany(count); // eslint-disable-next-line no-param-reassign @@ -248,7 +254,7 @@ class ArbitraryComponent extends BaseComponent { for (const i in this.map) { this.data[this.map[i]].dirty = false; } - this.dirty = false; + this.setDirty(false, 0); } createMany(entries) { @@ -264,6 +270,7 @@ class ArbitraryComponent extends BaseComponent { entity = entries[i]; } this.map[entity] = allocated[i]; + this.data[allocated[i]].entity = entity; for (const j in values) { if (this.schema.has(j)) { this.data[allocated[i]][j] = values[j]; @@ -281,12 +288,16 @@ class ArbitraryComponent extends BaseComponent { return this.get(entity); } - static instanceFromSchema(schema) { + instanceFromSchema() { + const Component = this; const Instance = class { + $$dirty = 1; + + $$entity = 0; + constructor() { - this.$$dirty = 1; - for (const [i, {defaultValue}] of schema) { + for (const [i, {defaultValue}] of Component.schema) { this[i] = defaultValue; } } @@ -301,7 +312,15 @@ class ArbitraryComponent extends BaseComponent { this.$$dirty = v; }, }; - for (const [i] of schema) { + properties.entity = { + get: function get() { + return this.$$entity; + }, + set: function set(v) { + this.$$entity = v; + }, + }; + for (const [i] of Component.schema) { properties[i] = { get: function get() { return this[`$$${i}`]; @@ -309,6 +328,7 @@ class ArbitraryComponent extends BaseComponent { set: function set(v) { this[`$$${i}`] = v; this.$$dirty = 1; + Component.setDirty(1, this.entity); }, }; } @@ -322,10 +342,11 @@ export default function ComponentRouter() { const schema = new Schema(this.constructor.schema); let RealClass; if (schema.width > 0) { - RealClass = FlatComponent; + RealClass = class extends FlatComponent {}; + RealClass.width = schema.width + 9; // 1 for dirty, 8 for entity } else { - RealClass = ArbitraryComponent; + RealClass = class extends ArbitraryComponent {}; } return new RealClass(schema); } diff --git a/packages/ecs/src/ecs.js b/packages/ecs/src/ecs.js index 20cf239..13116da 100644 --- a/packages/ecs/src/ecs.js +++ b/packages/ecs/src/ecs.js @@ -6,8 +6,6 @@ export default class Ecs { $$caret = 1; - $$cleanEntities = new Set(); - Components = {}; dirty = new Set(); @@ -20,24 +18,15 @@ export default class Ecs { constructor(Components) { for (const i in Components) { - class Component extends Components[i] { - - set dirty(dirty) { - super.dirty = dirty; - const it = this.$$cleanEntities.values(); - let result = it.next(); - while (!result.done) { - result = it.next(); - } - for (let i = 0; i < this.$$entities.length; i++) { - if (this.get(this.$$entities[i])) { - this.dirty.add(this.$$entities[i]); - } - } + const comp = new Components[i](); + const {setDirty} = comp; + comp.setDirty = (dirty, entity) => { + setDirty.call(comp, dirty); + if (entity) { + this.dirty.add(entity); } - - } - this.Components[i] = new Component(); + }; + this.Components[i] = comp; } } @@ -143,7 +132,7 @@ export default class Ecs { for (const i in this.Components) { this.Components[i].clean(); } - this.dirty = []; + this.dirty.clear(); } tickFinalize() { diff --git a/packages/ecs/src/index.js b/packages/ecs/src/index.js index 769082a..0bed1f3 100644 --- a/packages/ecs/src/index.js +++ b/packages/ecs/src/index.js @@ -65,7 +65,9 @@ for (let i = 0; i < warm; ++i) { } performance.mark('tick0'); ecs.tick(0.01); +console.log(ecs.dirty.size); ecs.tickFinalize(); +console.log(ecs.dirty.size); performance.mark('tick1'); console.log(ecs.$$systems[0].queries.default.count); @@ -78,6 +80,7 @@ console.log({ y: p.y, z: p.z, dirty: p.dirty, + entity: p.entity, }); console.log(performance.getEntriesByType('measure').map(({duration, name}) => ({duration, name}))); diff --git a/packages/ecs/src/schema.js b/packages/ecs/src/schema.js index 17883e2..f68f3e2 100644 --- a/packages/ecs/src/schema.js +++ b/packages/ecs/src/schema.js @@ -4,7 +4,7 @@ export default class Schema { defaultValues = {}; - width = 1; + width = 0; spec;