flow: firming up API

This commit is contained in:
cha0s 2024-12-01 20:34:17 -06:00
parent 7cc790f04a
commit 8d23144206
6 changed files with 92 additions and 52 deletions

View File

@ -37,18 +37,12 @@ class Component {
destroy() {
this.set(undefined);
}
get entity() {
return Component.ecs.get(this.entityId);
}
markChange(change) {
if (this.entityId) {
Component.ecs.markChange(this.entityId, constructor.componentName, change);
}
}
set(entityId, values = {}) {
if (entityId && this.entityId && this.entityId !== entityId) {
this.destroy();
}
this.entityId = entityId;
for (const key in properties) {
const propertyBlueprint = constructor.properties[key];
@ -69,12 +63,6 @@ class Component {
}
return json;
}
toNet(recipient, data) {
if (data) {
return data;
}
return this.toJSON();
}
};
for (const key in constructor.properties) {
const propertyBlueprint = constructor.properties[key];

View File

@ -3,7 +3,7 @@ import Entity from './entity.js';
class Ecs {
caret = 1;
$$destructionDependencies = new Map();
$$destructors = new Map();
$$diff;
changes = [];
Components = {};
@ -19,11 +19,11 @@ class Ecs {
}
}
addDestructionDependency(entity) {
if (!this.$$destructionDependencies.has(entity)) {
this.$$destructionDependencies.set(entity, {listeners: [], pending: new Set()})
addDestructor(entity) {
if (!this.$$destructors.has(entity)) {
this.$$destructors.set(entity, {listeners: [], pending: new Set()})
}
const {pending} = this.$$destructionDependencies.get(entity);
const {pending} = this.$$destructors.get(entity);
const token = {};
pending.add(token);
return () => {
@ -63,21 +63,21 @@ class Ecs {
}
destroy(entity, listener) {
if (!this.$$destructionDependencies.has(entity)) {
this.$$destructionDependencies.set(entity, {listeners: [], pending: new Set()});
if (!this.$$destructors.has(entity)) {
this.$$destructors.set(entity, {listeners: [], pending: new Set()});
}
const dependencies = this.$$destructionDependencies.get(entity);
const dependencies = this.$$destructors.get(entity);
if (listener) {
dependencies.listeners.push(listener);
}
}
destroyImmediately(entity) {
if (this.$$destructionDependencies.has(entity)) {
for (const listener of this.$$destructionDependencies.get(entity).listeners) {
if (this.$$destructors.has(entity)) {
for (const listener of this.$$destructors.get(entity).listeners) {
listener(entity);
}
this.$$destructionDependencies.delete(entity);
this.$$destructors.delete(entity);
}
this.deindex(entity);
this.entities.delete(entity.id);
@ -153,15 +153,6 @@ class Ecs {
}
}
reindexSingle(entity) {
for (const systemName in this.Systems) {
const System = this.Systems[systemName];
if (System.active) {
System.reindexSingle(entity);
}
}
}
setClean() {
this.$$diff = undefined;
this.changes = [];
@ -169,21 +160,9 @@ class Ecs {
tick(elapsed) {
for (const systemName in this.Systems) {
const System = this.Systems[systemName];
if (!System.active) {
continue;
}
if (!System.frequency) {
System.tick(elapsed);
continue;
}
System.elapsed += elapsed;
while (System.elapsed >= System.frequency) {
System.tick(System.frequency);
System.elapsed -= System.frequency;
}
this.Systems[systemName].tickWithChecks(elapsed);
}
for (const [entity, {pending}] of this.$$destructionDependencies) {
for (const [entity, {pending}] of this.$$destructors) {
if (0 === pending.size) {
this.destroyImmediately(entity);
}

View File

@ -64,7 +64,7 @@ test('destruction dependency', () => {
});
expect(wasDestroyed).to.be.false;
expect(ecs.entities.get(entity.id)).not.to.be.undefined;
const destroy = ecs.addDestructionDependency(entity);
const destroy = ecs.addDestructor(entity);
ecs.tick(0);
expect(wasDestroyed).to.be.false;
destroy();

View File

@ -1,7 +1,7 @@
export const Properties = {};
export function definitions(blueprint, key = 'value') {
const privateKey = `$$${key}`;
export function definitions(blueprint, key) {
const privateKey = `$$${key ?? 'value'}`;
return {
get: function() {
return this[privateKey];

View File

@ -14,6 +14,8 @@ export default class System {
queries = {};
scheduled = false;
constructor(ecs) {
this.ecs = ecs;
const queries = this.constructor.queries();
@ -45,7 +47,7 @@ export default class System {
}
schedule() {
this.elapsed = this.frequency;
this.scheduled = true;
}
select(query) {
@ -84,6 +86,25 @@ export default class System {
);
}
tick() {}
tickWithChecks(elapsed) {
if (!this.active) {
return;
}
if (!this.frequency) {
this.tick(elapsed);
return;
}
this.elapsed += elapsed;
if (this.scheduled) {
this.tick(this.elapsed);
this.elapsed = 0;
this.scheduled = false;
return;
}
while (this.elapsed >= this.frequency) {
this.tick(this.frequency);
this.elapsed -= this.frequency;
}
}
}

View File

@ -40,7 +40,7 @@ test('priority', () => {
static priority = {before: 'Normal'};
}
class BetweenNormalAndAfterBeforeNormal {
static priority = {before: 'AfterBeforeNormal', after: 'Normal'};
static priority = {before: ['AfterBeforeNormal'], after: ['Normal']};
}
class Normal extends System {}
expect(
@ -72,3 +72,55 @@ test('priority', () => {
'AfterBeforeNormal',
]);
});
test('tick', () => {
const ticks = [];
class Scheduled extends System {
tick(elapsed) {
ticks.push(elapsed);
}
}
const system = new Scheduled();
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([0.5]);
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([0.5, 0.5]);
system.active = false;
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([0.5, 0.5]);
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([0.5, 0.5]);
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([0.5, 0.5]);
system.active = true;
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([0.5, 0.5, 0.5]);
});
test('tick scheduling', () => {
const ticks = [];
class Scheduled extends System {
frequency = 1;
tick(elapsed) {
ticks.push(elapsed);
}
}
const system = new Scheduled();
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([]);
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([1]);
system.schedule();
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([1, 0.5]);
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([1, 0.5]);
system.active = false;
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([1, 0.5]);
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([1, 0.5]);
system.active = true;
system.tickWithChecks(0.5);
expect(ticks).to.deep.equal([1, 0.5, 1]);
});