UNPKG

@thi.ng/ecs

Version:

Entity Component System based around typed arrays & sparse sets

132 lines (131 loc) 3.92 kB
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 };