perf: use detached entities

This commit is contained in:
cha0s 2024-08-03 15:25:41 -05:00
parent 172b457a8c
commit 623aabf525
2 changed files with 33 additions and 42 deletions

View File

@ -8,32 +8,32 @@ export default class Emitter {
this.ecs = ecs;
this.scheduled = [];
}
async allocate({entity, fields, shape}) {
const allocated = this.ecs.get(await this.ecs.create(entity));
async configure(entityId, {fields, shape}) {
const entity = this.ecs.get(entityId);
if (shape) {
switch (shape.type) {
case 'circle': {
const r = Math.random() * TAU;
allocated.Position.x += Math.cos(r) * shape.payload.radius;
allocated.Position.y += Math.sin(r) * shape.payload.radius;
entity.Position.x += Math.cos(r) * shape.payload.radius;
entity.Position.y += Math.sin(r) * shape.payload.radius;
break;
}
case 'filledCircle': {
const r = Math.random() * TAU;
allocated.Position.x += Math.cos(r) * Math.random() * shape.payload.radius;
allocated.Position.y += Math.sin(r) * Math.random() * shape.payload.radius;
entity.Position.x += Math.cos(r) * Math.random() * shape.payload.radius;
entity.Position.y += Math.sin(r) * Math.random() * shape.payload.radius;
break;
}
case 'filledRect': {
allocated.Position.x += Math.random() * shape.payload.width - (shape.payload.width / 2);
allocated.Position.y += Math.random() * shape.payload.height - (shape.payload.height / 2);
entity.Position.x += Math.random() * shape.payload.width - (shape.payload.width / 2);
entity.Position.y += Math.random() * shape.payload.height - (shape.payload.height / 2);
break;
}
}
}
if (fields) {
for (const {easing = 'linear', path, value} of fields) {
let walk = allocated;
let walk = entity;
const pathCopy = path.slice(0);
const final = pathCopy.pop();
for (const key of pathCopy) {
@ -44,7 +44,7 @@ export default class Emitter {
walk[final] = easings[easing](c - i, value[i], value[i + 1] - value[i], 1);
}
}
return allocated;
return entity;
}
emit(particle) {
particle = {
@ -52,59 +52,47 @@ export default class Emitter {
entity: {
Position: {},
Sprite: {},
VisibleAabb: {},
...particle.entity,
},
}
let {count = 1} = particle;
const {frequency = 0} = particle;
const stream = K.stream((emitter) => {
const {entity, frequency = 0} = particle;
const specifications = Array(count);
for (let i = 0; i < count; ++i) {
specifications[i] = entity;
}
const stream = K.stream(async (emitter) => {
const entityIds = await this.ecs.createManyDetached(specifications);
if (0 === frequency) {
const promises = [];
for (let i = 0; i < count; ++i) {
promises.push(
this.allocate(particle)
.then((entity) => {
emitter.emit(entity);
}),
);
this.ecs.attach(entityIds);
for (const entityId of entityIds) {
emitter.emit(this.configure(entityId, particle));
}
Promise.all(promises)
.then(() => {
emitter.end();
});
emitter.end();
return;
}
const promise = this.allocate(particle)
.then((entity) => {
emitter.emit(entity);
});
const it = entityIds.values();
const entityId = it.next().value;
this.ecs.attach(new Set([entityId]));
emitter.emit(this.configure(entityId, particle));
count -= 1;
if (0 === count) {
promise.then(() => {
emitter.end();
});
emitter.end();
return;
}
const promises = [promise];
let accumulated = 0;
const scheduled = (elapsed) => {
accumulated += elapsed;
while (accumulated > frequency && count > 0) {
promises.push(
this.allocate(particle)
.then((entity) => {
emitter.emit(entity);
}),
);
const entityId = it.next().value;
this.ecs.attach(new Set([entityId]));
emitter.emit(this.configure(entityId, particle));
accumulated -= frequency;
count -= 1;
}
if (0 === count) {
this.scheduled.splice(this.scheduled.indexOf(scheduled), 1);
Promise.all(promises).then(() => {
emitter.end();
});
emitter.end();
}
};
this.scheduled.push(scheduled);

View File

@ -33,6 +33,9 @@ function tick(now) {
const lastNearby = new Set(memory.values());
for (const id in ecs.$$entities) {
const entity = ecs.$$entities[id];
if (ecs.$$detached.has(entity.id)) {
continue;
}
lastNearby.delete(id);
if (!memory.has(id)) {
update[id] = entity.toJSON();