@thi.ng/ecs
Version:
Entity Component System based around typed arrays & sparse sets
132 lines (131 loc) • 3.92 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp(target, key, result);
return result;
};
import { INotifyMixin } from "@thi.ng/api/mixins/inotify";
import { uintTypeForSize } from "@thi.ng/api/typedarray";
import { bitSize } from "@thi.ng/binary/count";
import { isArray } from "@thi.ng/checks/is-array";
import { isString } from "@thi.ng/checks/is-string";
import { assert } from "@thi.ng/errors/assert";
import { IDGen } from "@thi.ng/idgen";
import { NativePool } from "@thi.ng/malloc/native";
import { filter } from "@thi.ng/transducers/filter";
import {
EVENT_ADDED,
EVENT_PRE_DELETE
} from "./api.js";
import { MemMappedComponent } from "./components/mem-component.js";
import { ObjectComponent } from "./components/object-component.js";
import { Group } from "./groups/group.js";
let NEXT_GROUP_ID = 0;
let ECS = class {
idgen;
pool;
components;
groups;
constructor(opts) {
opts = { capacity: 1e3, pool: new NativePool(), ...opts };
this.idgen = new IDGen(bitSize(opts.capacity), 0);
this.pool = opts.pool;
this.components = /* @__PURE__ */ new Map();
this.groups = /* @__PURE__ */ new Map();
}
defEntity(comps) {
const id = this.idgen.next();
if (comps) {
if (isArray(comps)) {
if (!comps.length) return id;
for (let cid of comps) {
const comp = isString(cid) ? this.components.get(cid) : cid;
assert(!!comp, `unknown component ID: ${cid}`);
comp.add(id);
}
} else {
for (let cid in comps) {
const comp = this.components.get(cid);
assert(!!comp, `unknown component ID: ${cid}`);
comp.add(id, comps[cid]);
}
}
}
this.notify({ id: EVENT_ADDED, target: this, value: id });
return id;
}
defComponent(opts) {
assert(
!this.components.has(opts.id),
`component '${opts.id}' already existing`
);
const cap = this.idgen.capacity;
const utype = uintTypeForSize(cap);
const sparse = this.pool.mallocAs(utype, cap);
const dense = this.pool.mallocAs(utype, cap);
if (!(sparse && dense)) return;
const comp = opts.type !== void 0 ? new MemMappedComponent(dense, sparse, opts) : new ObjectComponent(sparse, dense, opts);
this.components.set(opts.id, comp);
return comp;
}
defGroup(comps, owned = comps, opts = {}) {
opts = {
id: `group${NEXT_GROUP_ID++}`,
...opts
};
assert(
!this.groups.has(opts.id),
`group '${opts.id}' already existing`
);
const g = new Group(comps, owned, opts);
this.groups.set(g.id, g);
return g;
}
hasID(id) {
this.idgen.has(id);
}
deleteID(id) {
if (this.idgen.free(id)) {
this.notify({ id: EVENT_PRE_DELETE, target: this, value: id });
for (let c of this.componentsForID(id)) {
c.delete(id);
}
return true;
}
return false;
}
componentsForID(id) {
return filter((c) => c.has(id), this.components.values());
}
groupsForID(id) {
return filter((g) => g.has(id), this.groups.values());
}
setCapacity(newCap) {
this.idgen.capacity = newCap;
const pool = this.pool;
for (let comp of this.components.values()) {
comp.resize(pool, newCap);
}
}
// @ts-ignore: mixin
// prettier-ignore
addListener(id, fn, scope) {
}
// @ts-ignore: mixin
// prettier-ignore
removeListener(id, fn, scope) {
}
// @ts-ignore: mixin
notify(event) {
}
};
ECS = __decorateClass([
INotifyMixin
], ECS);
export {
ECS
};