flow: firming up API
This commit is contained in:
parent
7cc790f04a
commit
8d23144206
|
@ -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];
|
||||
|
|
47
src/ecs.js
47
src/ecs.js
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user