ecsjs 1.2.0 → 1.3.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ecs.js CHANGED
@@ -1,2 +1,2 @@
1
- var C="ComponentMap",y="ComponentClassesMap";var i=class extends Map{firstEntry(){return this.size===0?void 0:this.entries().next().value}firstKey(){return this.size===0?void 0:this.keys().next().value}firstValue(){return this.size===0?void 0:this.values().next().value}toJSON(){return{[C]:1,iterable:[...this.entries()]}}toTable(n=!1){let e=[];for(let[t,o]of this.entries()){let s=o,r={};n==!1&&(r["entity.key"]=t),r["entity.type"]=s.constructor.name,e.push({...r,...s})}return e}printTable(n=!1){console.table(this.toTable(n))}static get[Symbol.species](){return Map}},m=class extends Map{toJSON(){return{[y]:1,iterable:[...this.entries()]}}static get[Symbol.species](){return Map}};var c=class extends Error{constructor(){super("Component type is missing the 'name' parameter. i.e. a constructor name")}},p=class extends Error{constructor(e){super(`Component map does not exist for '${e}'`);this.componentName=e}};var l=class{constructor(n,e,...t){this.ecs=n;this.key=e;this.keyMap=this.ecs.getMap(e),this.entries=this.keyMap.entries(),this.components=t.map(o=>this.ecs.getMap(o))}keyMap;components;entries;next(){let n=this.entries.next(),{value:e,done:t}=n;if(t)return{value:e,done:t};let[o,s]=e,r=[o,s];for(let d of this.components)r.push(d.get(o));return{value:r,done:!1}}reset(){this.entries=this.keyMap.entries()}[Symbol.iterator](){return this}};var u=class a{components=new m;nextId=0;register(...n){for(let e of n){let t=e.name;if(t===void 0)throw new c;let o=new i;this.components.set(t,o)}return this}getMap(n){let e=this.components.get(n.name);if(e===void 0)throw new p(n.name);return e}firstEntry(n,...e){return e.length===0?this.getMap(n)?.firstEntry():this.firstKey(n,n,...e)}firstKey(n,...e){let t=this.getMap(n)?.firstKey();if(arguments.length===1)return t;if(t!==void 0)return[t,...e.map(o=>this.getEntity(t,o))]}firstValue(n,...e){if(arguments.length===1)return this.getMap(n)?.firstValue();let[t,o]=this.getMap(n)?.firstEntry()??[];if(t!==void 0)return[o,...e.map(s=>this.getEntity(t,s))]}getEntity(n,e){let t=this.components.get(e.name);if(t===void 0)throw new p(e.name);return t.get(n)}get(n,...e){return e.length>1?e.map(t=>this.getEntity(n,t)):this.getEntity(n,e[0])}has(n,e){let t=this.components.get(e.name);return t===void 0?!1:t.has(n)}hasAll(n,...e){for(let t=0;t<e.length;t++){let o=e[t],s=this.components.get(o.name);if(s===void 0||s.has(n)===!1)return!1}return!0}hasAny(n,...e){for(let t=0;t<e.length;t++){let o=e[t],s=this.components.get(o.name);if(s!==void 0&&s.has(n))return!0}return!1}setEntity(n,e){let t=this.components.get(e.constructor.name);if(t===void 0)throw new p(e.constructor.name);return t.set(n,e),e}set(n,...e){return e.length>1?e.map(t=>this.setEntity(n,t)):this.setEntity(n,e[0])}remove(n,...e){for(let t of e)this.removeByKey(n,t.name)}removeByKey(n,e){let t=this.components.get(e);if(t===void 0)throw new p(e);return t.get(n)===void 0?!1:t.delete(n)}destroyEntity(...n){let e=0;for(let t=0;t<n.length;t++){let o=n[t];for(let s of this.components.values())s.has(o)&&(s.delete(o),e++)}return e}getNextId(){return this.nextId++,this.nextId}clear(){return this.components.clear(),this}clearComponents(){return this.components.forEach(n=>n.clear()),this}iterator(n,...e){return new l(this,n,...e)}printTable(){return this.components.forEach(n=>console.table(n.toTable(!0))),this}printEntity(n){for(let e of this.components.values()){if(e.has(n)===!1)continue;let t=e.get(n),o={name:t.constructor.name,...t};console.table({[n]:o})}return this}static parse(n){return JSON.parse(n,function(t,o){return o.hasOwnProperty("components")?(Reflect.setPrototypeOf(o,a.prototype),o):o.hasOwnProperty(C)?new i(o.iterable):o.hasOwnProperty(y)?new m(o.iterable):this[t]})}static createWithTracing(n){let e={get(t,o){let s=t[o];return typeof s=="function"&&(n.length===0||n.includes(o))?function(...r){return console.groupCollapsed("ecs trace",o,r),console.trace(),console.groupEnd(),s.apply(this,r)}:s}};return new Proxy(new a,e)}};var f=new u;typeof window<"u"?window.ecs=f:typeof module<"u"&&module!==null&&(module.exports={ecs:f});export{m as ComponentClassesMap,l as ComponentIterator,i as ComponentMap,u as EntityMap,f as ecs};
1
+ var d="ComponentMap",f="ComponentClassesMap";var m=class extends Map{firstEntry(){return this.size===0?void 0:this.entries().next().value}firstKey(){return this.size===0?void 0:this.keys().next().value}firstValue(){return this.size===0?void 0:this.values().next().value}toJSON(){return{[d]:1,iterable:[...this.entries()]}}toTable(e=!1){let t=[];for(let[n,s]of this.entries()){let o=s,r={};e==!1&&(r["entity.key"]=n),r["entity.type"]=o.constructor.name,t.push({...r,...o})}return t}printTable(e=!1){console.table(this.toTable(e))}static get[Symbol.species](){return Map}},l=class extends Map{toJSON(){return{[f]:1,iterable:[...this.entries()]}}static get[Symbol.species](){return Map}};var c=class extends Error{constructor(){super("Component type is missing the 'name' parameter. i.e. a constructor name")}},i=class extends Error{constructor(t){super(`Component map does not exist for '${t}'`);this.componentName=t}};var p=class{keyMap;componentMaps=[];entries;constructor(e){this.keyMap=e.keyMap,this.componentMaps=e.componentMaps,this.entries=this.keyMap.entries()}next(){let e=this.entries.next(),{value:t,done:n}=e;if(n)return{value:t,done:n};let[s,o]=t,r=[s,o];for(let C=0;C<this.componentMaps.length;C++){let T=this.componentMaps[C];r.push(T.get(s))}return{value:r,done:!1}}reset(){this.entries=this.keyMap.entries()}[Symbol.iterator](){return this}};var u=class{constructor(e,...t){this.ecs=e;this.keyMap=this.ecs.getMap(t[0]);for(let n=1;n<t.length;n++)this.componentMaps.push(this.ecs.getMap(t[n]))}keyMap;componentMaps=[];firstEntry(){if(this.componentMaps.length===0)return this.keyMap.firstEntry();let[e,t]=this.keyMap.firstEntry()??[];if(e===void 0)return;let n=[e,t];for(let s=0;s<this.componentMaps.length;s++)n.push(this.componentMaps[s].get(e));return n}firstKey(){let e=this.keyMap.firstKey();if(this.componentMaps.length===0)return e;if(e===void 0)return;let t=[e];for(let n=0;n<this.componentMaps.length;n++)t.push(this.componentMaps[n].get(e));return t}firstValue(){if(this.componentMaps.length===0)return this.keyMap.firstValue();let[e,t]=this.keyMap.firstEntry()??[];if(e===void 0)return;let n=[t];for(let s=0;s<this.componentMaps.length;s++)n.push(this.componentMaps[s].get(e));return n}[Symbol.iterator](){return new p(this)}};var y=class a{components=new l;nextId=0;register(...e){for(let t of e){let n=t.name;if(n===void 0)throw new c;let s=new m;this.components.set(n,s)}return this}getMap(e){let t=this.components.get(e.name);if(t===void 0)throw new i(e.name);return t}firstEntry(e,...t){return t.length===0?this.getMap(e)?.firstEntry():this.firstKey(e,e,...t)}firstKey(e,...t){let n=this.getMap(e)?.firstKey();if(arguments.length===1)return n;if(n!==void 0)return[n,...t.map(s=>this.getEntity(n,s))]}firstValue(e,...t){if(arguments.length===1)return this.getMap(e)?.firstValue();let[n,s]=this.getMap(e)?.firstEntry()??[];if(n!==void 0)return[s,...t.map(o=>this.getEntity(n,o))]}getEntity(e,t){let n=this.components.get(t.name);if(n===void 0)throw new i(t.name);return n.get(e)}get(e,...t){return t.length>1?t.map(n=>this.getEntity(e,n)):this.getEntity(e,t[0])}has(e,t){let n=this.components.get(t.name);return n===void 0?!1:n.has(e)}hasAll(e,...t){for(let n=0;n<t.length;n++){let s=t[n],o=this.components.get(s.name);if(o===void 0||o.has(e)===!1)return!1}return!0}hasAny(e,...t){for(let n=0;n<t.length;n++){let s=t[n],o=this.components.get(s.name);if(o!==void 0&&o.has(e))return!0}return!1}setEntity(e,t){let n=this.components.get(t.constructor.name);if(n===void 0)throw new i(t.constructor.name);return n.set(e,t),t}set(e,...t){return t.length>1?t.map(n=>this.setEntity(e,n)):this.setEntity(e,t[0])}remove(e,...t){for(let n of t)this.removeByKey(e,n.name)}removeByKey(e,t){let n=this.components.get(t);if(n===void 0)throw new i(t);return n.get(e)===void 0?!1:n.delete(e)}destroyEntity(...e){let t=0;for(let n=0;n<e.length;n++){let s=e[n];for(let o of this.components.values())o.has(s)&&(o.delete(s),t++)}return t}getNextId(){return this.nextId++,this.nextId}clear(){return this.components.clear(),this}clearComponents(){return this.components.forEach(e=>e.clear()),this}iterator(e,...t){return new p(new u(this,e,...t))}query(e,...t){return new u(this,e,...t)}printTable(){return this.components.forEach(e=>console.table(e.toTable(!0))),this}printEntity(e){for(let t of this.components.values()){if(t.has(e)===!1)continue;let n=t.get(e),s={name:n.constructor.name,...n};console.table({[e]:s})}return this}static parse(e){return JSON.parse(e,function(n,s){return s.hasOwnProperty("components")?(Reflect.setPrototypeOf(s,a.prototype),s):s.hasOwnProperty(d)?new m(s.iterable):s.hasOwnProperty(f)?new l(s.iterable):this[n]})}static createWithTracing(e){let t={get(n,s){let o=n[s];return typeof o=="function"&&(e.length===0||e.includes(s))?function(...r){return console.groupCollapsed("ecs trace",s,r),console.trace(),console.groupEnd(),o.apply(this,r)}:o}};return new Proxy(new a,t)}};var h=new y;typeof window<"u"?window.ecs=h:typeof module<"u"&&module!==null&&(module.exports={ecs:h});export{l as ComponentClassesMap,p as ComponentIterator,m as ComponentMap,u as ComponentQuery,y as EntityMap,h as ecs};
2
2
  //# sourceMappingURL=ecs.js.map
package/dist/ecs.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/types.ts", "../src/component-map.ts", "../src/errors.ts", "../src/iterators.ts", "../src/entity-map.ts", "../src/ecs.ts"],
4
- "sourcesContent": ["export const ComponentMapKey = \"ComponentMap\"\nexport const ComponentClassesMapKey = \"ComponentClassesMap\"\n\nexport type KeyCollection<T> = { [key: string]: T }\n\nexport interface Component { }\n\n/**\n * @category Types\n * @example\n * \n * class PositionComponent {\n * constructor(x, y) {\n * this.x = x;\n * this.y = y;\n * }\n * }\n */\nexport type ComponentClass<ComponentInstance> = new (...args: any[]) => ComponentInstance\n\n/**\n* Used for infering generic type spread for classes\n*/\nexport type ComponentClasses<TClasses extends Component[]> =\n { [Index in keyof TClasses]: TClasses[Index] }\n\n/**\n * Used for infering generic type spread for class instances\n */\nexport type ComponentInstances<TClasses extends ComponentClass<any>[]> =\n // return a single variadic item when only 1 item is specified\n TClasses['length'] extends 1 ? TClasses[0] extends ComponentClass<infer R> ? R : never\n // otherwise return an array of variadic types\n : {\n [Index in keyof TClasses]: TClasses[Index] extends ComponentClass<infer R> ? R : never\n }\n\nexport type IteratorResult<T> = {\n done: boolean,\n value: T\n}\n\nexport type Iterator<T> = {\n next: () => IteratorResult<T>\n reset: () => void\n [Symbol.iterator]: () => Iterator<T>\n}\n\n/**\n * allow late bound assignment type for intellisense\n * @category Types\n * @example\n * \n * let someIterator: IComponentIterator<[Player, Position]>\n * \n * // assignment made somewhere else in the code\n * const [player, position] = someIterator(Player, Position) ?? []\n * position?.x = 123 // position will have intellisense\n */\nexport type IComponentIterator<T extends Component[]>\n = Iterator<ComponentClasses<[number, ...T]>>", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { ComponentClassesMapKey, ComponentMapKey, type KeyCollection } from './types.js';\n\n/**\n * Component map for storing entity ids and related component data\n * @category Maps\n */\nexport class ComponentMap<TComponentInstance> extends Map<number, TComponentInstance> {\n\n /**\n * Returns the first entity entry\n */\n firstEntry(): [entityId: number, value: TComponentInstance] | undefined {\n if (this.size === 0) return undefined;\n\n const iterator = this.entries();\n const result = iterator.next();\n return result.value;\n }\n\n /**\n * Returns the first entity id\n */\n firstKey(): number | undefined {\n if (this.size === 0) return undefined;\n\n const iterator = this.keys();\n const result = iterator.next();\n return result.value;\n }\n\n /**\n * Returns the first entity value\n */\n firstValue(): TComponentInstance | undefined {\n if (this.size === 0) return undefined;\n\n const iterator = this.values();\n const result = iterator.next();\n return result.value;\n }\n\n /**\n * Called when using JSON.stringify\n */\n toJSON() {\n return { [ComponentMapKey]: 1, iterable: [...this.entries()] };\n }\n\n toTable(excludeKeys = false): any[] {\n const table = []\n for (const [key, value] of this.entries()) {\n const entity = value as { new(): TComponentInstance };\n const meta: KeyCollection<any> = {};\n if (excludeKeys == false) meta[\"entity.key\"] = key;\n meta[\"entity.type\"] = entity.constructor.name;\n table.push({ ...meta, ...entity });\n }\n return table;\n }\n\n /**\n * Prints entity data in a tabular format to the console\n */\n printTable(excludeKeys = false): void {\n console.table(this.toTable(excludeKeys));\n }\n\n static get [Symbol.species]() {\n return Map;\n }\n\n}\n\n/**\n * Component class map for storing registered component maps\n * @category Maps\n */\nexport class ComponentClassesMap extends Map<string, ComponentMap<any>> {\n\n /**\n * Called when using JSON.stringify\n */\n toJSON() {\n return { [ComponentClassesMapKey]: 1, iterable: [...this.entries()] };\n }\n\n static get [Symbol.species]() {\n return Map;\n }\n\n}", "/**\n * Thrown when trying to register a component that is missing a 'name' parameter\n * @category Errors\n */\nexport class ComponentTypeKeyMissing extends Error {\n constructor() {\n super(`Component type is missing the 'name' parameter. i.e. a constructor name`);\n }\n}\n\n/**\n * Thrown when trying to access a component that has not been registered\n * @category Errors\n */\nexport class ComponentNotRegistered extends Error {\n constructor(public componentName: string) {\n super(`Component map does not exist for '${componentName}'`);\n }\n}", "import type { ComponentMap } from './component-map.js';\nimport type { EntityMap } from './entity-map.js';\nimport type { ComponentClass, ComponentInstances, IteratorResult } from './types.js';\n\n/**\n * @category Iterators\n * @example\n * // construct an instance\n * const iterator = new ComponentIterator(entityMap, Player, Position)\n * \n * // iterate each component value that is related to the Player\n * for(const [entityId, player, position] of iterator) { }\n * \n * // you can also reset the iterator back to the start \n * // without having to create a new ComponentIterator instance\n * iterator.reset()\n * for(const [entityId, player, position] of iterator) { }\n */\nexport class ComponentIterator<\n TComponentKey extends ComponentClass<any>,\n TComponentClasses extends ComponentClass<any>[]\n> {\n\n private keyMap: ComponentMap<any>\n private components: ComponentMap<any>[]\n // iteration state\n private entries: MapIterator<[number, TComponentKey]>\n\n /**\n * {@link ComponentNotRegistered} when any of specified component(s) are not registered\n */\n constructor(public ecs: EntityMap, public key: TComponentKey, ...components: TComponentClasses) {\n this.keyMap = this.ecs.getMap(key)!;\n this.entries = this.keyMap.entries();\n this.components = components.map(x => this.ecs.getMap(x)!);\n }\n\n /**\n * gets the next iterator value\n */\n next(): IteratorResult<ComponentInstances<[ComponentClass<number>, TComponentKey, ...TComponentClasses]>> {\n const entry = this.entries.next();\n const { value, done } = entry;\n if (done) return { value: value as any, done };\n\n const [entityId, entityValue] = value;\n const results = [entityId, entityValue]\n for (const x of this.components) {\n results.push(x.get(entityId));\n }\n\n return { value: results as any, done: false };\n }\n\n /**\n * resets the iterator back to the first entry\n */\n reset() {\n this.entries = this.keyMap.entries();\n }\n\n [Symbol.iterator]() { return this; }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { ComponentClassesMap, ComponentMap } from './component-map.js';\nimport { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js';\nimport { ComponentIterator } from './iterators.js';\nimport {\n ComponentClassesMapKey,\n ComponentMapKey,\n type Component,\n type ComponentClass,\n type ComponentInstances\n} from './types.js';\n\n/**\n * Class for storing entities and their relationships\n * @category Maps\n */\nexport class EntityMap {\n /**\n * Registered component classes that contain the component instance data\n */\n public components = new ComponentClassesMap()\n\n private nextId: number = 0\n\n /**\n * Registers component classes with the {@link EntityMap}\n * @throwsError {@link ComponentTypeKeyMissing} when the specified component type is missing a 'name' parameter\n * @example\n * // component class\n * class MyComponent {\n * constructor(x) {\n * this.x = x;\n * }\n * }\n *\n * ecs.register(MyComponent);\n * // or mulitple\n * ecs.register(MyComponent1, MyComponent2);\n */\n register<TComponentClasses extends ComponentClass<any>[]>(...componentClasses: TComponentClasses) {\n for (const componentClass of componentClasses) {\n const componentName = componentClass.name;\n if (componentName === undefined) throw new ComponentTypeKeyMissing()\n\n // create the component map\n const componentDataMap: ComponentMap<any> = new ComponentMap();\n this.components.set(componentName, componentDataMap);\n }\n\n // chain\n return this;\n }\n\n /**\n * Gets a component class map\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * const positionMap = ecs.getMap(Position)\n * for(const [entityId, position] of positionMap) {\n * position.x += 1\n * }\n */\n getMap<T>(component: ComponentClass<T>): ComponentMap<T> | undefined {\n const map = this.components.get(component.name);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n return map\n }\n\n /**\n * Gets the first entity entry for a component class\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // return the first entry\n * const [entityId, player] = ecs.firstEntry(Player) ?? []\n * \n * // or return multiple related components in addition to the first entry\n * const [entityId, player, position, direction] = ecs.firstEntry(\n * Player,\n * Position,\n * Direction\n * )\n */\n firstEntry<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(\n keyComponent: TKey,\n ...components: T\n ): ComponentInstances<[ComponentClass<number>, TKey, ...T]> | undefined;\n firstEntry(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n if (components.length === 0) return this.getMap(keyComponent)?.firstEntry()\n\n return this.firstKey(keyComponent, keyComponent, ...components);\n }\n\n /**\n * Gets the first entity id for a component class \n * and optionally any related component data\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first entity id\n * const entityId = ecs.firstKey(Player)\n * \n * // or return multiple related component in addition to entity id\n * const [entityId, position, direction] = ecs.firstKey(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstKey<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(\n keyComponent: TKey,\n ...components: T\n ): ComponentInstances<[ComponentClass<number>, ...T]> | undefined;\n firstKey(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n const entityId = this.getMap(keyComponent)?.firstKey();\n\n // single component key\n if (arguments.length === 1) return entityId;\n if (entityId === undefined) return undefined;\n\n // attach multiple related component values\n return [entityId, ...components.map(x => this.getEntity(entityId, x))];\n }\n\n /**\n * Gets the first entity component data for a component class\n * and optionally any related component data\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first component value\n * const player = ecs.firstValue(Player)\n * \n * // or multiple related values in addition to the first component\n * const [player, position, direction] = ecs.firstValue(\n * Player,\n * Position,\n * Direction\n * )\n */\n firstValue<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(\n keyComponent: TKey,\n ...components: T\n ): ComponentInstances<[TKey, ...T]> | undefined;\n firstValue(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n // single component\n if (arguments.length === 1) return this.getMap(keyComponent)?.firstValue();\n\n // get the first entry\n const [entityId, value] = this.getMap(keyComponent)?.firstEntry() ?? [];\n if (entityId === undefined) return undefined;\n\n // attach multiple related components\n return [value, ...components.map(x => this.getEntity(entityId, x))]\n }\n\n /**\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered \n */\n private getEntity<T>(entityId: number, component: ComponentClass<T>): T | undefined {\n const map = this.components.get(component.name);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n\n return map.get(entityId);\n }\n\n /**\n * Gets component values related to an entity id\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // get one\n * const player = ecs.get(entityId, Player)\n * \n * // or get multiple\n * const [player, position] = ecs.get(entityId, Player, Position) ?? []\n */\n get<T extends ComponentClass<any>[]>(entityId: number, ...components: T): ComponentInstances<T> | undefined;\n get<T extends Component>(entityId: number, ...components: ComponentClass<T>[]): T | (T | undefined)[] | undefined {\n if (components.length > 1) return components.map(x => this.getEntity(entityId, x))\n\n // return a single component\n return this.getEntity(entityId, components[0])\n }\n\n /**\n * Check if a component exists for an entity\n * @example\n * const exists = ecs.has(entityId, Position)\n */\n has<T>(entityId: number, component: ComponentClass<T>): boolean {\n // get the component map\n const map = this.components.get(component.name);\n if (map === undefined) return false\n\n return map.has(entityId);\n }\n\n /**\n * Checks if all of the specified components exist for an entity\n * @example\n * const hasAll = ecs.hasAll(entityId, Position, Velocity)\n */\n hasAll<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component.name);\n if (map === undefined) return false;\n if (map.has(entityId) === false) return false;\n }\n return true\n }\n\n /**\n * Checks if any of the specified components exist for an entity\n * @example\n * const hasAny = ecs.hasAny(entityId, Position, Velocity)\n */\n hasAny<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component.name);\n if (map === undefined) continue;\n if (map.has(entityId)) return true;\n }\n return false\n }\n\n private setEntity<T extends Component>(entityId: number, componentData: T): T {\n // get the component map\n const map = this.components.get(componentData.constructor.name);\n if (map === undefined) throw new ComponentNotRegistered(componentData.constructor.name)\n\n // set the entity on the entity map\n map.set(entityId, componentData);\n\n // return instance\n return componentData;\n }\n\n /**\n * Add or update multiple component values for an entity\n * @example\n * // set one\n * const player = ecs.set(entityId, new Player());\n * \n * // or set multiple\n * const [player, position] = ecs.set(\n * entityId,\n * new Player(),\n * new Position()\n * );\n */\n set<T extends Component>(entityId: number, component: T): T;\n set<T extends Component[]>(entityId: number, ...components: T): T;\n set(entityId: number, ...components: Component[]): Component | Component[] {\n if (components.length > 1) return components.map(x => this.setEntity(entityId, x))\n\n // set and return a single component\n return this.setEntity(entityId, components[0])\n }\n\n /**\n * Removes the specified component(s) from an entity\n * @example\n * ecs.remove(entityId, Position);\n */\n remove<T extends ComponentClass<any>[]>(entityId: number, ...components: T) {\n for (const component of components) {\n this.removeByKey(entityId, component.name)\n }\n }\n\n /**\n * Removes the specified component from an entity\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * ecs.removeByKey(entityId, \"Position\");\n */\n removeByKey(entityId: number, componentName: string) {\n // get the entity map\n const entityMap = this.components.get(componentName);\n\n // ensure the map is defined\n if (entityMap === undefined) throw new ComponentNotRegistered(componentName);\n\n // get the entity\n const entity = entityMap.get(entityId);\n if (entity === undefined) return false;\n\n // remove the entity from the entity map\n return entityMap.delete(entityId);\n }\n\n /**\n * Deletes all components from an entity\n * @example\n * const destroyedCount = ecs.destroyEntity(entityId1)\n * \n * // or multiple\n * const destroyedCount = ecs.destroyEntity(entityId1, entityId2)\n */\n destroyEntity(...entityIds: number[]): number {\n let deletedCount = 0;\n for (let index = 0; index < entityIds.length; index++) {\n const entityId = entityIds[index];\n for (const map of this.components.values()) {\n if (map.has(entityId)) {\n map.delete(entityId);\n deletedCount++;\n }\n }\n }\n return deletedCount;\n }\n\n // TODO create id generator\n /**\n * Creates a new entity id for the EntityMap\n * @example\n * const newEntityId = ecs.getNextId()\n * ecs.set(newEntityId, new Player())\n */\n getNextId(): number {\n this.nextId++;\n return this.nextId;\n }\n\n /**\n * Clears all registered components\n */\n clear() {\n this.components.clear();\n return this;\n }\n\n /**\n * Clears all component data\n */\n clearComponents() {\n this.components.forEach(x => x.clear())\n return this;\n }\n\n /**\n * Iterates over each component value that is related to the key component\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // iterate each component value that is related to the Player entity\n * const iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) { }\n * \n * // you can also declare the type of iterator before it's assigned\n * let iterator: IComponentIterator<[Player, Position]>\n * \n * // then with late bound assignment (keeping the iterator intellisense)\n * iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) {\n * const moving = player.isMoving\n * }\n */\n iterator<K extends ComponentClass<any>, T extends ComponentClass<any>[]>(\n keyComponent: K,\n ...components: T\n ): ComponentIterator<K, T>\n iterator(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n return new ComponentIterator(this, keyComponent, ...components) as any;\n }\n\n /**\n * Prints all component maps in a tabular format to the console\n */\n printTable() {\n this.components.forEach(map => console.table(map.toTable(true)));\n return this;\n }\n\n /**\n * Prints all component data for the specified entity id in a tabular format to the console\n */\n printEntity(entityId: number) {\n for (const map of this.components.values()) {\n if (map.has(entityId) === false) continue;\n\n const data = map.get(entityId);\n const columns = {\n name: data.constructor.name,\n ...data\n };\n console.table({ [entityId]: columns });\n }\n\n return this;\n }\n\n /**\n * Parse's the JSON and returns an EntityMap object\n * @example\n * const json = JSON.stringfy(ecs);\n * const restoredMap = ecs.parse(json);\n */\n static parse(json: string): EntityMap {\n const restored = JSON.parse(json, function (key: string, value: any) {\n if (value.hasOwnProperty('components')) {\n Reflect.setPrototypeOf(value, EntityMap.prototype);\n return value;\n }\n if (value.hasOwnProperty(ComponentMapKey)) return new ComponentMap(value.iterable);\n if (value.hasOwnProperty(ComponentClassesMapKey)) return new ComponentClassesMap(value.iterable);\n return this[key];\n });\n return restored;\n }\n\n /**\n * A tracing method used for debugging.\n * Intercepts all functions specified and logs each call to the console.\n * @param {Array} funcFilter A list of function names you want to intercept. If no function names are specified then will log all functions called\n * @return {EntityMap} A new entity map with tracing enabled\n */\n static createWithTracing(funcFilter: any) {\n const traceHandler = {\n get(target: any, propKey: string) {\n const targetValue = target[propKey]\n\n if (typeof targetValue === 'function' && (funcFilter.length === 0 || funcFilter.includes(propKey))) {\n return function (this: any, ...args: any[]) {\n console.groupCollapsed('ecs trace', propKey, args);\n console.trace();\n console.groupEnd();\n return targetValue.apply(this, args);\n }\n }\n\n return targetValue;\n }\n }\n\n return new Proxy(new EntityMap(), traceHandler)\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * An entity component system library for JavaScript\n * @showCategories\n * @module ecsjs\n */\nimport { EntityMap } from './entity-map.js'\nexport { ComponentClassesMap, ComponentMap } from './component-map.js'\nexport { EntityMap } from './entity-map.js'\nexport type { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js'\nexport { ComponentIterator } from './iterators.js'\nexport type { ComponentClass, IComponentIterator } from './types.js'\n\n/**\n * Global instance of an {@link EntityMap}\n * \n * See the [cheat sheet](https://gitlab.com/ecsjs/ecs/-/blob/master/docs/cheat-sheet.md) for more examples\n * @category Constants\n * @example\n * \n * // register component(s)\n * ecs.register(Player, Position)\n * \n * // create an entity\n * const [player, position] = ecs.set(ecs.getNextId(), new Player(), new Position(10, 40))\n */\nexport const ecs = new EntityMap()\n\nif (typeof window !== 'undefined') {\n // @ts-ignore: exports to window\n window.ecs = ecs\n} else if (typeof module !== 'undefined' && module !== null) {\n // exports to nodejs\n module.exports = { ecs };\n}"],
5
- "mappings": "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",
6
- "names": ["ComponentMapKey", "ComponentClassesMapKey", "ComponentMap", "ComponentMapKey", "excludeKeys", "table", "key", "value", "entity", "meta", "ComponentClassesMap", "ComponentClassesMapKey", "ComponentTypeKeyMissing", "ComponentNotRegistered", "componentName", "ComponentIterator", "ecs", "key", "components", "x", "entry", "value", "done", "entityId", "entityValue", "results", "EntityMap", "_EntityMap", "ComponentClassesMap", "componentClasses", "componentClass", "componentName", "ComponentTypeKeyMissing", "componentDataMap", "ComponentMap", "component", "map", "ComponentNotRegistered", "keyComponent", "components", "entityId", "x", "value", "index", "componentData", "entityMap", "entityIds", "deletedCount", "ComponentIterator", "data", "columns", "json", "key", "ComponentMapKey", "ComponentClassesMapKey", "funcFilter", "traceHandler", "target", "propKey", "targetValue", "args", "ecs", "EntityMap"]
3
+ "sources": ["../src/types.ts", "../src/component-map.ts", "../src/errors.ts", "../src/iterator.ts", "../src/query.ts", "../src/entity-map.ts", "../src/ecs.ts"],
4
+ "sourcesContent": ["export const ComponentMapKey = \"ComponentMap\"\nexport const ComponentClassesMapKey = \"ComponentClassesMap\"\n\nexport type KeyCollection<T> = { [key: string]: T }\n\nexport interface Component { }\n\n/**\n * @category Types\n * @example\n * \n * class PositionComponent {\n * constructor(x, y) {\n * this.x = x;\n * this.y = y;\n * }\n * }\n */\nexport type ComponentClass<ComponentInstance> = new (...args: any[]) => ComponentInstance\n\n/**\n* Used for infering generic type spread for classes\n*/\nexport type ComponentClasses<T extends Component[]> =\n { [Index in keyof T]: ComponentClass<T[Index]> }\n\nexport type SingleOrArray<T extends any[]> =\n // return a single variadic item when only 1 item is specified\n T['length'] extends 1 ? T[0]\n // otherwise return an array of variadic types\n : { [Index in keyof T]: T[Index] }\n\n/**\n * Used for infering generic type spread for class instances\n */\nexport type ComponentInstances<TClasses extends ComponentClass<any>[]> =\n // return a single variadic item when only 1 item is specified\n TClasses['length'] extends 1 ? TClasses[0] extends ComponentClass<infer R> ? R : never\n // otherwise return an array of variadic types\n : {\n [Index in keyof TClasses]: TClasses[Index] extends ComponentClass<infer R> ? R : never\n }\n\nexport type IteratorResult<T> = {\n done: boolean,\n value: T\n}\n\nexport type Iterator<T> = {\n next: () => IteratorResult<T>\n reset: () => void\n [Symbol.iterator]: () => Iterator<T>\n}\n\n/**\n * allow late bound assignment type for intellisense\n * @category Types\n * @example\n * \n * let someIterator: IComponentIterator<[Player, Position]>\n * \n * // assignment made somewhere else in the code\n * const [player, position] = someIterator(Player, Position) ?? []\n * position?.x = 123 // position will have intellisense\n */\nexport type IComponentIterator<T extends Component[]>\n = Iterator<ComponentClasses<[number, ...T]>>", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { ComponentClassesMapKey, ComponentMapKey, type KeyCollection } from './types.js';\n\n/**\n * Component map for storing entity ids and related component data\n * @category Maps\n */\nexport class ComponentMap<TComponentInstance> extends Map<number, TComponentInstance> {\n\n /**\n * Returns the first entity entry\n */\n firstEntry(): [entityId: number, value: TComponentInstance] | undefined {\n if (this.size === 0) return undefined;\n\n const iterator = this.entries();\n const result = iterator.next();\n return result.value;\n }\n\n /**\n * Returns the first entity id\n */\n firstKey(): number | undefined {\n if (this.size === 0) return undefined;\n\n const iterator = this.keys();\n const result = iterator.next();\n return result.value;\n }\n\n /**\n * Returns the first entity value\n */\n firstValue(): TComponentInstance | undefined {\n if (this.size === 0) return undefined;\n\n const iterator = this.values();\n const result = iterator.next();\n return result.value;\n }\n\n /**\n * Called when using JSON.stringify\n */\n toJSON() {\n return { [ComponentMapKey]: 1, iterable: [...this.entries()] };\n }\n\n toTable(excludeKeys = false): any[] {\n const table = []\n for (const [key, value] of this.entries()) {\n const entity = value as { new(): TComponentInstance };\n const meta: KeyCollection<any> = {};\n if (excludeKeys == false) meta[\"entity.key\"] = key;\n meta[\"entity.type\"] = entity.constructor.name;\n table.push({ ...meta, ...entity });\n }\n return table;\n }\n\n /**\n * Prints entity data in a tabular format to the console\n */\n printTable(excludeKeys = false): void {\n console.table(this.toTable(excludeKeys));\n }\n\n static get [Symbol.species]() {\n return Map;\n }\n\n}\n\n/**\n * Component class map for storing registered component maps\n * @category Maps\n */\nexport class ComponentClassesMap extends Map<string, ComponentMap<any>> {\n\n /**\n * Called when using JSON.stringify\n */\n toJSON() {\n return { [ComponentClassesMapKey]: 1, iterable: [...this.entries()] };\n }\n\n static get [Symbol.species]() {\n return Map;\n }\n\n}", "/**\n * Thrown when trying to register a component that is missing a 'name' parameter\n * @category Errors\n */\nexport class ComponentTypeKeyMissing extends Error {\n constructor() {\n super(`Component type is missing the 'name' parameter. i.e. a constructor name`);\n }\n}\n\n/**\n * Thrown when trying to access a component that has not been registered\n * @category Errors\n */\nexport class ComponentNotRegistered extends Error {\n constructor(public componentName: string) {\n super(`Component map does not exist for '${componentName}'`);\n }\n}", "import type { ComponentMap } from './component-map.js';\nimport type { ComponentQuery } from './query.js';\nimport type { IteratorResult } from './types.js';\n\n/**\n * @category Iterators\n * @example\n * // construct an instance\n * const iterator = new ComponentIterator(new ComponentQuery(entityMap, Player, Position))\n * \n * // iterate each component value that is related to the Player\n * for(const [entityId, player, position] of iterator) { }\n * \n * // you can also reset the iterator back to the start\n * // without having to create a new ComponentIterator instance\n * iterator.reset()\n * for(const [entityId, player, position] of iterator) { }\n */\nexport class ComponentIterator<TKey, TRelated extends any[]> {\n private keyMap: ComponentMap<TKey>;\n private componentMaps: ComponentMap<any>[] = [];\n // iteration state\n private entries: MapIterator<[number, TKey]>;\n\n constructor(query: ComponentQuery<TKey, TRelated>) {\n // @ts-ignore\n this.keyMap = query.keyMap\n // @ts-ignore\n this.componentMaps = query.componentMaps\n this.entries = this.keyMap.entries();\n }\n\n /**\n * gets the next iterator value\n */\n next(): IteratorResult<[number, TKey, ...TRelated]> {\n const entry = this.entries.next();\n const { value, done } = entry;\n if (done) return { value: value as any, done };\n\n const [entityId, entityValue] = value;\n const results = [entityId, entityValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n const map = this.componentMaps[i];\n results.push(map.get(entityId));\n }\n\n return { value: results as any, done: false };\n }\n\n /**\n * resets the iterator back to the first entry\n */\n reset() {\n this.entries = this.keyMap.entries();\n }\n\n [Symbol.iterator]() { return this; }\n\n}", "import type { ComponentMap } from './component-map.js';\nimport type { EntityMap } from './entity-map.js';\nimport { ComponentIterator } from './iterator.js';\nimport type { ComponentClass, ComponentClasses, SingleOrArray } from './types.js';\n\n/**\n * @category Queries\n * @example\n * const query = ecs.query(Player, Position)\n * \n * // get the first entry\n * const [playerId, player, position] = query.firstEntry() ?? []\n * \n * // get the first key\n * const [playerId, position] = query.firstKey() ?? []\n * \n * // get the first value\n * const [player, position] = query.firstValue() ?? []\n * \n * // iterate\n * for (const [playerId, player, position] of query) {\n * \n * }\n */\nexport class ComponentQuery<TKey, TRelated extends any[]> {\n private keyMap: ComponentMap<TKey>\n private componentMaps: ComponentMap<any>[] = []\n \n /**\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n */\n constructor(\n public ecs: EntityMap,\n ...components: [ComponentClass<TKey>, ...ComponentClasses<TRelated>]\n ) {\n this.keyMap = this.ecs.getMap(components[0])!;\n for (let i = 1; i < components.length; i++) {\n this.componentMaps.push(this.ecs.getMap(components[i])!)\n }\n }\n\n /**\n * Returns the first entity entry\n * Also returns related components specified in the query constructor\n */\n firstEntry(): [number, TKey, ...TRelated] | undefined;\n firstEntry() {\n if (this.componentMaps.length === 0) return this.keyMap.firstEntry()\n\n const [entityId, entryValue] = this.keyMap.firstEntry() ?? []\n if (entityId === undefined) return undefined;\n\n const results: any[] = [entityId, entryValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Returns the first entity id\n * Also returns related components specified in the query constructor\n */\n firstKey(): SingleOrArray<[number, ...TRelated]> | undefined;\n firstKey() {\n const entityId = this.keyMap.firstKey()\n if (this.componentMaps.length === 0) return entityId;\n if (entityId === undefined) return undefined;\n\n const results: any[] = [entityId]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Returns the first value\n * Also returns related components specified in the query constructor\n */\n firstValue(): SingleOrArray<[TKey, ...TRelated]> | undefined;\n firstValue() {\n if (this.componentMaps.length === 0) return this.keyMap.firstValue()\n\n const [entityId, keyValue] = this.keyMap.firstEntry() ?? []\n if (entityId === undefined) return undefined;\n\n const results = [keyValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n [Symbol.iterator]() {\n return new ComponentIterator(this);\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { ComponentClassesMap, ComponentMap } from './component-map.js';\nimport { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js';\nimport { ComponentIterator } from './iterator.js';\nimport { ComponentQuery } from './query.js';\nimport {\n ComponentClassesMapKey,\n ComponentMapKey,\n type Component,\n type ComponentClass,\n type ComponentClasses,\n type ComponentInstances,\n type SingleOrArray,\n} from './types.js';\n\n/**\n * Class for storing entities and their relationships\n * @category Maps\n */\nexport class EntityMap {\n /**\n * Registered component classes that contain the component instance data\n */\n public components = new ComponentClassesMap()\n\n private nextId: number = 0\n\n /**\n * Registers component classes with the {@link EntityMap}\n * @throwsError {@link ComponentTypeKeyMissing} when the specified component type is missing a 'name' parameter\n * @example\n * // component class\n * class MyComponent {\n * constructor(x) {\n * this.x = x;\n * }\n * }\n *\n * ecs.register(MyComponent);\n * // or mulitple\n * ecs.register(MyComponent1, MyComponent2);\n */\n register<TComponentClasses extends ComponentClass<any>[]>(...componentClasses: TComponentClasses) {\n for (const componentClass of componentClasses) {\n const componentName = componentClass.name;\n if (componentName === undefined) throw new ComponentTypeKeyMissing()\n\n // create the component map\n const componentDataMap: ComponentMap<any> = new ComponentMap();\n this.components.set(componentName, componentDataMap);\n }\n\n // chain\n return this;\n }\n\n /**\n * Gets a component class map\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * const positionMap = ecs.getMap(Position)\n * for(const [entityId, position] of positionMap) {\n * position.x += 1\n * }\n */\n getMap<T>(component: ComponentClass<T>): ComponentMap<T> | undefined {\n const map = this.components.get(component.name);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n return map\n }\n\n /**\n * Gets the first entity entry for a component class\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // return the first entry\n * const [entityId, player] = ecs.firstEntry(Player) ?? []\n * \n * // or return multiple related components in addition to the first entry\n * const [entityId, player, position, direction] = ecs.firstEntry(\n * Player,\n * Position,\n * Direction\n * )\n */\n firstEntry<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ): [number, TKey, ...TRelated] | undefined;\n firstEntry(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n if (components.length === 0) return this.getMap(keyComponent)?.firstEntry()\n\n return this.firstKey(keyComponent, keyComponent, ...components);\n }\n\n /**\n * Gets the first entity id for a component class \n * and optionally any related component data\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first entity id\n * const entityId = ecs.firstKey(Player)\n * \n * // or return multiple related component in addition to entity id\n * const [entityId, position, direction] = ecs.firstKey(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstKey<TKey, TRelated extends any[]>(\n keyComponent: TKey,\n ...components: ComponentClasses<TRelated>\n ): SingleOrArray<[number, ...TRelated]> | undefined;\n firstKey(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n const entityId = this.getMap(keyComponent)?.firstKey();\n\n // single component key\n if (arguments.length === 1) return entityId;\n if (entityId === undefined) return undefined;\n\n // attach related component values\n return [entityId, ...components.map(x => this.getEntity(entityId, x))];\n }\n\n /**\n * Gets the first entity component data for a component class\n * and optionally any related component data\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first component value\n * const player = ecs.firstValue(Player)\n * \n * // or multiple related values in addition to the first component\n * const [player, position, direction] = ecs.firstValue(\n * Player,\n * Position,\n * Direction\n * )\n */\n firstValue<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ): SingleOrArray<[TKey, ...TRelated]> | undefined;\n firstValue(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n // single component\n if (arguments.length === 1) return this.getMap(keyComponent)?.firstValue();\n\n // get the first entry\n const [entityId, keyValue] = this.getMap(keyComponent)?.firstEntry() ?? [];\n if (entityId === undefined) return undefined;\n\n // attach related components\n return [keyValue, ...components.map(x => this.getEntity(entityId, x))]\n }\n\n /**\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered \n */\n private getEntity<T>(entityId: number, component: ComponentClass<T>): T | undefined {\n const map = this.components.get(component.name);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n\n return map.get(entityId);\n }\n\n /**\n * Gets component values related to an entity id\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // get one\n * const player = ecs.get(entityId, Player)\n * \n * // or get multiple\n * const [player, position] = ecs.get(entityId, Player, Position) ?? []\n */\n get<T extends ComponentClass<any>[]>(entityId: number, ...components: T): ComponentInstances<T> | undefined;\n get<T extends Component>(entityId: number, ...components: ComponentClass<T>[]): T | (T | undefined)[] | undefined {\n if (components.length > 1) return components.map(x => this.getEntity(entityId, x))\n\n // return a single component\n return this.getEntity(entityId, components[0])\n }\n\n /**\n * Check if a component exists for an entity\n * @example\n * const exists = ecs.has(entityId, Position)\n */\n has<T>(entityId: number, component: ComponentClass<T>): boolean {\n // get the component map\n const map = this.components.get(component.name);\n if (map === undefined) return false\n\n return map.has(entityId);\n }\n\n /**\n * Checks if all of the specified components exist for an entity\n * @example\n * const hasAll = ecs.hasAll(entityId, Position, Velocity)\n */\n hasAll<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component.name);\n if (map === undefined) return false;\n if (map.has(entityId) === false) return false;\n }\n return true\n }\n\n /**\n * Checks if any of the specified components exist for an entity\n * @example\n * const hasAny = ecs.hasAny(entityId, Position, Velocity)\n */\n hasAny<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component.name);\n if (map === undefined) continue;\n if (map.has(entityId)) return true;\n }\n return false\n }\n\n private setEntity<T extends Component>(entityId: number, componentData: T): T {\n // get the component map\n const map = this.components.get(componentData.constructor.name);\n if (map === undefined) throw new ComponentNotRegistered(componentData.constructor.name)\n\n // set the entity on the entity map\n map.set(entityId, componentData);\n\n // return instance\n return componentData;\n }\n\n /**\n * Add or update multiple component values for an entity\n * @example\n * // set one\n * const player = ecs.set(entityId, new Player());\n * \n * // or set multiple\n * const [player, position] = ecs.set(\n * entityId,\n * new Player(),\n * new Position()\n * );\n */\n set<T extends Component>(entityId: number, component: T): T;\n set<T extends Component[]>(entityId: number, ...components: T): T;\n set(entityId: number, ...components: Component[]): Component | Component[] {\n if (components.length > 1) return components.map(x => this.setEntity(entityId, x))\n\n // set and return a single component\n return this.setEntity(entityId, components[0])\n }\n\n /**\n * Removes the specified component(s) from an entity\n * @example\n * ecs.remove(entityId, Position);\n */\n remove<T extends ComponentClass<any>[]>(entityId: number, ...components: T) {\n for (const component of components) {\n this.removeByKey(entityId, component.name)\n }\n }\n\n /**\n * Removes the specified component from an entity\n * @throwsError {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * ecs.removeByKey(entityId, \"Position\");\n */\n removeByKey(entityId: number, componentName: string) {\n // get the entity map\n const entityMap = this.components.get(componentName);\n\n // ensure the map is defined\n if (entityMap === undefined) throw new ComponentNotRegistered(componentName);\n\n // get the entity\n const entity = entityMap.get(entityId);\n if (entity === undefined) return false;\n\n // remove the entity from the entity map\n return entityMap.delete(entityId);\n }\n\n /**\n * Deletes all components from an entity\n * @example\n * const destroyedCount = ecs.destroyEntity(entityId1)\n * \n * // or multiple\n * const destroyedCount = ecs.destroyEntity(entityId1, entityId2)\n */\n destroyEntity(...entityIds: number[]): number {\n let deletedCount = 0;\n for (let index = 0; index < entityIds.length; index++) {\n const entityId = entityIds[index];\n for (const map of this.components.values()) {\n if (map.has(entityId)) {\n map.delete(entityId);\n deletedCount++;\n }\n }\n }\n return deletedCount;\n }\n\n // TODO create id generator\n /**\n * Creates a new entity id for the EntityMap\n * @example\n * const newEntityId = ecs.getNextId()\n * ecs.set(newEntityId, new Player())\n */\n getNextId(): number {\n this.nextId++;\n return this.nextId;\n }\n\n /**\n * Clears all registered components\n */\n clear() {\n this.components.clear();\n return this;\n }\n\n /**\n * Clears all component data\n */\n clearComponents() {\n this.components.forEach(x => x.clear())\n return this;\n }\n\n /**\n * Iterates over each component value that is related to the key component\n * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // iterate each component value that is related to the Player entity\n * const iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) { }\n * \n * // you can also declare the type of iterator before it's assigned\n * let iterator: IComponentIterator<[Player, Position]>\n * \n * // then with late bound assignment (keeping the iterator intellisense)\n * iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) {\n * const moving = player.isMoving\n * }\n */\n iterator<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ) {\n return new ComponentIterator(new ComponentQuery(this, keyComponent, ...components));\n }\n\n /**\n * Creates a query that can be stored and reused\n * \n * @param keyComponent\n * @param components\n * @example\n * const query = ecs.query(Player, Position)\n * \n * // get the first entry\n * const [playerId, player, position] = query.firstEntry() ?? []\n * \n * // get the first key\n * const [playerId, position] = query.firstKey() ?? []\n * \n * // get the first value\n * const [player, position] = query.firstValue() ?? []\n * \n * // iterate\n * for (const [playerId, player, position] of query) {\n * \n * }\n */\n query<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ) {\n return new ComponentQuery(this, keyComponent, ...components)\n }\n\n /**\n * Prints all component maps in a tabular format to the console\n */\n printTable() {\n this.components.forEach(map => console.table(map.toTable(true)));\n return this;\n }\n\n /**\n * Prints all component data for the specified entity id in a tabular format to the console\n */\n printEntity(entityId: number) {\n for (const map of this.components.values()) {\n if (map.has(entityId) === false) continue;\n\n const data = map.get(entityId);\n const columns = {\n name: data.constructor.name,\n ...data\n };\n console.table({ [entityId]: columns });\n }\n\n return this;\n }\n\n /**\n * Parse's the JSON and returns an EntityMap object\n * @example\n * const json = JSON.stringfy(ecs);\n * const restoredMap = ecs.parse(json);\n */\n static parse(json: string): EntityMap {\n const restored = JSON.parse(json, function (key: string, value: any) {\n if (value.hasOwnProperty('components')) {\n Reflect.setPrototypeOf(value, EntityMap.prototype);\n return value;\n }\n if (value.hasOwnProperty(ComponentMapKey)) return new ComponentMap(value.iterable);\n if (value.hasOwnProperty(ComponentClassesMapKey)) return new ComponentClassesMap(value.iterable);\n return this[key];\n });\n return restored;\n }\n\n /**\n * A tracing method used for debugging.\n * Intercepts all functions specified and logs each call to the console.\n * @param {Array} funcFilter A list of function names you want to intercept. If no function names are specified then will log all functions called\n * @return {EntityMap} A new entity map with tracing enabled\n */\n static createWithTracing(funcFilter: any) {\n const traceHandler = {\n get(target: any, propKey: string) {\n const targetValue = target[propKey]\n\n if (typeof targetValue === 'function' && (funcFilter.length === 0 || funcFilter.includes(propKey))) {\n return function (this: any, ...args: any[]) {\n console.groupCollapsed('ecs trace', propKey, args);\n console.trace();\n console.groupEnd();\n return targetValue.apply(this, args);\n }\n }\n\n return targetValue;\n }\n }\n\n return new Proxy(new EntityMap(), traceHandler)\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * An entity component system library for JavaScript\n * @showCategories\n * @module ecsjs\n */\nimport { EntityMap } from './entity-map.js'\nexport { ComponentClassesMap, ComponentMap } from './component-map.js'\nexport { EntityMap } from './entity-map.js'\nexport type { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js'\nexport { ComponentIterator } from './iterator.js'\nexport { ComponentQuery } from './query.js'\nexport type { ComponentClass, IComponentIterator } from './types.js'\n\n/**\n * Global instance of an {@link EntityMap}\n * \n * See the [cheat sheet](https://gitlab.com/ecsjs/ecs/-/blob/master/docs/cheat-sheet.md) for more examples\n * @category Constants\n * @example\n * \n * // register component(s)\n * ecs.register(Player, Position)\n * \n * // create an entity\n * const [player, position] = ecs.set(ecs.getNextId(), new Player(), new Position(10, 40))\n */\nexport const ecs = new EntityMap()\n\nif (typeof window !== 'undefined') {\n // @ts-ignore: exports to window\n window.ecs = ecs\n} else if (typeof module !== 'undefined' && module !== null) {\n // exports to nodejs\n module.exports = { ecs };\n}"],
5
+ "mappings": "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",
6
+ "names": ["ComponentMapKey", "ComponentClassesMapKey", "ComponentMap", "ComponentMapKey", "excludeKeys", "table", "key", "value", "entity", "meta", "ComponentClassesMap", "ComponentClassesMapKey", "ComponentTypeKeyMissing", "ComponentNotRegistered", "componentName", "ComponentIterator", "query", "entry", "value", "done", "entityId", "entityValue", "results", "i", "map", "ComponentQuery", "ecs", "components", "i", "entityId", "entryValue", "results", "keyValue", "ComponentIterator", "EntityMap", "_EntityMap", "ComponentClassesMap", "componentClasses", "componentClass", "componentName", "ComponentTypeKeyMissing", "componentDataMap", "ComponentMap", "component", "map", "ComponentNotRegistered", "keyComponent", "components", "entityId", "x", "keyValue", "index", "componentData", "entityMap", "entityIds", "deletedCount", "ComponentIterator", "ComponentQuery", "data", "columns", "json", "key", "value", "ComponentMapKey", "ComponentClassesMapKey", "funcFilter", "traceHandler", "target", "propKey", "targetValue", "args", "ecs", "EntityMap"]
7
7
  }
@@ -7,7 +7,8 @@ import { EntityMap } from './entity-map.js';
7
7
  export { ComponentClassesMap, ComponentMap } from './component-map.js';
8
8
  export { EntityMap } from './entity-map.js';
9
9
  export type { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js';
10
- export { ComponentIterator } from './iterators.js';
10
+ export { ComponentIterator } from './iterator.js';
11
+ export { ComponentQuery } from './query.js';
11
12
  export type { ComponentClass, IComponentIterator } from './types.js';
12
13
  /**
13
14
  * Global instance of an {@link EntityMap}
@@ -1 +1 @@
1
- {"version":3,"file":"ecs.d.ts","sourceRoot":"","sources":["../../../src/ecs.ts"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG,WAAkB,CAAA"}
1
+ {"version":3,"file":"ecs.d.ts","sourceRoot":"","sources":["../../../src/ecs.ts"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG,WAAkB,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { ComponentClassesMap, ComponentMap } from './component-map.js';
2
- import { ComponentIterator } from './iterators.js';
3
- import { type Component, type ComponentClass, type ComponentInstances } from './types.js';
2
+ import { ComponentIterator } from './iterator.js';
3
+ import { ComponentQuery } from './query.js';
4
+ import { type Component, type ComponentClass, type ComponentClasses, type ComponentInstances, type SingleOrArray } from './types.js';
4
5
  /**
5
6
  * Class for storing entities and their relationships
6
7
  * @category Maps
@@ -51,7 +52,7 @@ export declare class EntityMap {
51
52
  * Direction
52
53
  * )
53
54
  */
54
- firstEntry<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(keyComponent: TKey, ...components: T): ComponentInstances<[ComponentClass<number>, TKey, ...T]> | undefined;
55
+ firstEntry<TKey, TRelated extends any[]>(keyComponent: ComponentClass<TKey>, ...components: ComponentClasses<TRelated>): [number, TKey, ...TRelated] | undefined;
55
56
  /**
56
57
  * Gets the first entity id for a component class
57
58
  * and optionally any related component data
@@ -67,7 +68,7 @@ export declare class EntityMap {
67
68
  * Direction
68
69
  * ) ?? []
69
70
  */
70
- firstKey<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(keyComponent: TKey, ...components: T): ComponentInstances<[ComponentClass<number>, ...T]> | undefined;
71
+ firstKey<TKey, TRelated extends any[]>(keyComponent: TKey, ...components: ComponentClasses<TRelated>): SingleOrArray<[number, ...TRelated]> | undefined;
71
72
  /**
72
73
  * Gets the first entity component data for a component class
73
74
  * and optionally any related component data
@@ -83,7 +84,7 @@ export declare class EntityMap {
83
84
  * Direction
84
85
  * )
85
86
  */
86
- firstValue<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(keyComponent: TKey, ...components: T): ComponentInstances<[TKey, ...T]> | undefined;
87
+ firstValue<TKey, TRelated extends any[]>(keyComponent: ComponentClass<TKey>, ...components: ComponentClasses<TRelated>): SingleOrArray<[TKey, ...TRelated]> | undefined;
87
88
  /**
88
89
  * @throwsError {@link ComponentNotRegistered} when the specified component is not registered
89
90
  */
@@ -189,7 +190,30 @@ export declare class EntityMap {
189
190
  * const moving = player.isMoving
190
191
  * }
191
192
  */
192
- iterator<K extends ComponentClass<any>, T extends ComponentClass<any>[]>(keyComponent: K, ...components: T): ComponentIterator<K, T>;
193
+ iterator<TKey, TRelated extends any[]>(keyComponent: ComponentClass<TKey>, ...components: ComponentClasses<TRelated>): ComponentIterator<TKey, TRelated>;
194
+ /**
195
+ * Creates a query that can be stored and reused
196
+ *
197
+ * @param keyComponent
198
+ * @param components
199
+ * @example
200
+ * const query = ecs.query(Player, Position)
201
+ *
202
+ * // get the first entry
203
+ * const [playerId, player, position] = query.firstEntry() ?? []
204
+ *
205
+ * // get the first key
206
+ * const [playerId, position] = query.firstKey() ?? []
207
+ *
208
+ * // get the first value
209
+ * const [player, position] = query.firstValue() ?? []
210
+ *
211
+ * // iterate
212
+ * for (const [playerId, player, position] of query) {
213
+ *
214
+ * }
215
+ */
216
+ query<TKey, TRelated extends any[]>(keyComponent: ComponentClass<TKey>, ...components: ComponentClasses<TRelated>): ComponentQuery<TKey, TRelated>;
193
217
  /**
194
218
  * Prints all component maps in a tabular format to the console
195
219
  */
@@ -1 +1 @@
1
- {"version":3,"file":"entity-map.d.ts","sourceRoot":"","sources":["../../../src/entity-map.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"entity-map.d.ts","sourceRoot":"","sources":["../../../src/entity-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ComponentQuery } from './query.js';
2
+ import type { IteratorResult } from './types.js';
3
+ /**
4
+ * @category Iterators
5
+ * @example
6
+ * // construct an instance
7
+ * const iterator = new ComponentIterator(new ComponentQuery(entityMap, Player, Position))
8
+ *
9
+ * // iterate each component value that is related to the Player
10
+ * for(const [entityId, player, position] of iterator) { }
11
+ *
12
+ * // you can also reset the iterator back to the start
13
+ * // without having to create a new ComponentIterator instance
14
+ * iterator.reset()
15
+ * for(const [entityId, player, position] of iterator) { }
16
+ */
17
+ export declare class ComponentIterator<TKey, TRelated extends any[]> {
18
+ private keyMap;
19
+ private componentMaps;
20
+ private entries;
21
+ constructor(query: ComponentQuery<TKey, TRelated>);
22
+ /**
23
+ * gets the next iterator value
24
+ */
25
+ next(): IteratorResult<[number, TKey, ...TRelated]>;
26
+ /**
27
+ * resets the iterator back to the first entry
28
+ */
29
+ reset(): void;
30
+ [Symbol.iterator](): this;
31
+ }
32
+ //# sourceMappingURL=iterator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iterator.d.ts","sourceRoot":"","sources":["../../../src/iterator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAiB,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE;IACzD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,aAAa,CAA2B;IAEhD,OAAO,CAAC,OAAO,CAA8B;gBAEjC,KAAK,EAAE,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC;IAQjD;;OAEG;IACH,IAAI,IAAI,cAAc,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IAenD;;OAEG;IACH,KAAK;IAIL,CAAC,MAAM,CAAC,QAAQ,CAAC;CAElB"}
@@ -0,0 +1,48 @@
1
+ import type { EntityMap } from './entity-map.js';
2
+ import { ComponentIterator } from './iterator.js';
3
+ import type { ComponentClass, ComponentClasses, SingleOrArray } from './types.js';
4
+ /**
5
+ * @category Queries
6
+ * @example
7
+ * const query = ecs.query(Player, Position)
8
+ *
9
+ * // get the first entry
10
+ * const [playerId, player, position] = query.firstEntry() ?? []
11
+ *
12
+ * // get the first key
13
+ * const [playerId, position] = query.firstKey() ?? []
14
+ *
15
+ * // get the first value
16
+ * const [player, position] = query.firstValue() ?? []
17
+ *
18
+ * // iterate
19
+ * for (const [playerId, player, position] of query) {
20
+ *
21
+ * }
22
+ */
23
+ export declare class ComponentQuery<TKey, TRelated extends any[]> {
24
+ ecs: EntityMap;
25
+ private keyMap;
26
+ private componentMaps;
27
+ /**
28
+ * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered
29
+ */
30
+ constructor(ecs: EntityMap, ...components: [ComponentClass<TKey>, ...ComponentClasses<TRelated>]);
31
+ /**
32
+ * Returns the first entity entry
33
+ * Also returns related components specified in the query constructor
34
+ */
35
+ firstEntry(): [number, TKey, ...TRelated] | undefined;
36
+ /**
37
+ * Returns the first entity id
38
+ * Also returns related components specified in the query constructor
39
+ */
40
+ firstKey(): SingleOrArray<[number, ...TRelated]> | undefined;
41
+ /**
42
+ * Returns the first value
43
+ * Also returns related components specified in the query constructor
44
+ */
45
+ firstValue(): SingleOrArray<[TKey, ...TRelated]> | undefined;
46
+ [Symbol.iterator](): ComponentIterator<TKey, TRelated>;
47
+ }
48
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE;IAQ7C,GAAG,EAAE,SAAS;IAPvB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAA0B;IAE/C;;OAEG;gBAEM,GAAG,EAAE,SAAS,EACrB,GAAG,UAAU,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAQtE;;;OAGG;IACH,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,SAAS;IAerD;;;OAGG;IACH,QAAQ,IAAI,aAAa,CAAC,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAc5D;;;OAGG;IACH,UAAU,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAe5D,CAAC,MAAM,CAAC,QAAQ,CAAC;CAIlB"}
@@ -20,8 +20,11 @@ export type ComponentClass<ComponentInstance> = new (...args: any[]) => Componen
20
20
  /**
21
21
  * Used for infering generic type spread for classes
22
22
  */
23
- export type ComponentClasses<TClasses extends Component[]> = {
24
- [Index in keyof TClasses]: TClasses[Index];
23
+ export type ComponentClasses<T extends Component[]> = {
24
+ [Index in keyof T]: ComponentClass<T[Index]>;
25
+ };
26
+ export type SingleOrArray<T extends any[]> = T['length'] extends 1 ? T[0] : {
27
+ [Index in keyof T]: T[Index];
25
28
  };
26
29
  /**
27
30
  * Used for infering generic type spread for class instances
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAC7C,eAAO,MAAM,sBAAsB,wBAAwB,CAAA;AAE3D,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAA;AAEnD,MAAM,WAAW,SAAS;CAAI;AAE9B;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,CAAC,iBAAiB,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,iBAAiB,CAAA;AAEzF;;EAEE;AACF,MAAM,MAAM,gBAAgB,CAAC,QAAQ,SAAS,SAAS,EAAE,IACvD;KAAG,KAAK,IAAI,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC;CAAE,CAAA;AAEhD;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,QAAQ,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,IAEnE,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAEpF;KACC,KAAK,IAAI,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACvF,CAAA;AAEH,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,CAAC,CAAA;CACT,CAAA;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,IAAI,EAAE,MAAM,cAAc,CAAC,CAAC,CAAC,CAAA;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAA;CACrC,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,SAAS,EAAE,IAChD,QAAQ,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,iBAAiB,CAAA;AAC7C,eAAO,MAAM,sBAAsB,wBAAwB,CAAA;AAE3D,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAA;AAEnD,MAAM,WAAW,SAAS;CAAI;AAE9B;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,CAAC,iBAAiB,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,iBAAiB,CAAA;AAEzF;;EAEE;AACF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,SAAS,EAAE,IAChD;KAAG,KAAK,IAAI,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CAAE,CAAA;AAElD,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,GAAG,EAAE,IAEvC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAE1B;KAAG,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;CAAE,CAAA;AAEpC;;GAEG;AACH,MAAM,MAAM,kBAAkB,CAAC,QAAQ,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,IAEnE,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAEpF;KACC,KAAK,IAAI,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CACvF,CAAA;AAEH,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,CAAC,CAAA;CACT,CAAA;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,IAAI,EAAE,MAAM,cAAc,CAAC,CAAC,CAAC,CAAA;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAA;CACrC,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,SAAS,EAAE,IAChD,QAAQ,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "title": "ECS JS",
3
3
  "name": "ecsjs",
4
- "version": "1.2.0",
4
+ "version": "1.3.0-alpha.2",
5
5
  "description": "An entity component system library for JavaScript",
6
6
  "author": "2013+ pflannery (https://gitlab.com/pflannery)",
7
7
  "license": "GNU GPL v3",
@@ -56,4 +56,4 @@
56
56
  "test": "task",
57
57
  "prepublishOnly": "task bundle"
58
58
  }
59
- }
59
+ }
package/src/ecs.ts CHANGED
@@ -25,7 +25,8 @@ import { EntityMap } from './entity-map.js'
25
25
  export { ComponentClassesMap, ComponentMap } from './component-map.js'
26
26
  export { EntityMap } from './entity-map.js'
27
27
  export type { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js'
28
- export { ComponentIterator } from './iterators.js'
28
+ export { ComponentIterator } from './iterator.js'
29
+ export { ComponentQuery } from './query.js'
29
30
  export type { ComponentClass, IComponentIterator } from './types.js'
30
31
 
31
32
  /**
package/src/entity-map.ts CHANGED
@@ -17,13 +17,16 @@
17
17
  */
18
18
  import { ComponentClassesMap, ComponentMap } from './component-map.js';
19
19
  import { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js';
20
- import { ComponentIterator } from './iterators.js';
20
+ import { ComponentIterator } from './iterator.js';
21
+ import { ComponentQuery } from './query.js';
21
22
  import {
22
23
  ComponentClassesMapKey,
23
24
  ComponentMapKey,
24
25
  type Component,
25
26
  type ComponentClass,
26
- type ComponentInstances
27
+ type ComponentClasses,
28
+ type ComponentInstances,
29
+ type SingleOrArray,
27
30
  } from './types.js';
28
31
 
29
32
  /**
@@ -96,10 +99,10 @@ export class EntityMap {
96
99
  * Direction
97
100
  * )
98
101
  */
99
- firstEntry<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(
100
- keyComponent: TKey,
101
- ...components: T
102
- ): ComponentInstances<[ComponentClass<number>, TKey, ...T]> | undefined;
102
+ firstEntry<TKey, TRelated extends any[]>(
103
+ keyComponent: ComponentClass<TKey>,
104
+ ...components: ComponentClasses<TRelated>
105
+ ): [number, TKey, ...TRelated] | undefined;
103
106
  firstEntry(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {
104
107
  if (components.length === 0) return this.getMap(keyComponent)?.firstEntry()
105
108
 
@@ -121,10 +124,10 @@ export class EntityMap {
121
124
  * Direction
122
125
  * ) ?? []
123
126
  */
124
- firstKey<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(
127
+ firstKey<TKey, TRelated extends any[]>(
125
128
  keyComponent: TKey,
126
- ...components: T
127
- ): ComponentInstances<[ComponentClass<number>, ...T]> | undefined;
129
+ ...components: ComponentClasses<TRelated>
130
+ ): SingleOrArray<[number, ...TRelated]> | undefined;
128
131
  firstKey(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {
129
132
  const entityId = this.getMap(keyComponent)?.firstKey();
130
133
 
@@ -132,7 +135,7 @@ export class EntityMap {
132
135
  if (arguments.length === 1) return entityId;
133
136
  if (entityId === undefined) return undefined;
134
137
 
135
- // attach multiple related component values
138
+ // attach related component values
136
139
  return [entityId, ...components.map(x => this.getEntity(entityId, x))];
137
140
  }
138
141
 
@@ -151,20 +154,20 @@ export class EntityMap {
151
154
  * Direction
152
155
  * )
153
156
  */
154
- firstValue<TKey extends ComponentClass<any>, T extends ComponentClass<any>[]>(
155
- keyComponent: TKey,
156
- ...components: T
157
- ): ComponentInstances<[TKey, ...T]> | undefined;
157
+ firstValue<TKey, TRelated extends any[]>(
158
+ keyComponent: ComponentClass<TKey>,
159
+ ...components: ComponentClasses<TRelated>
160
+ ): SingleOrArray<[TKey, ...TRelated]> | undefined;
158
161
  firstValue(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {
159
162
  // single component
160
163
  if (arguments.length === 1) return this.getMap(keyComponent)?.firstValue();
161
164
 
162
165
  // get the first entry
163
- const [entityId, value] = this.getMap(keyComponent)?.firstEntry() ?? [];
166
+ const [entityId, keyValue] = this.getMap(keyComponent)?.firstEntry() ?? [];
164
167
  if (entityId === undefined) return undefined;
165
168
 
166
- // attach multiple related components
167
- return [value, ...components.map(x => this.getEntity(entityId, x))]
169
+ // attach related components
170
+ return [keyValue, ...components.map(x => this.getEntity(entityId, x))]
168
171
  }
169
172
 
170
173
  /**
@@ -373,12 +376,40 @@ export class EntityMap {
373
376
  * const moving = player.isMoving
374
377
  * }
375
378
  */
376
- iterator<K extends ComponentClass<any>, T extends ComponentClass<any>[]>(
377
- keyComponent: K,
378
- ...components: T
379
- ): ComponentIterator<K, T>
380
- iterator(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {
381
- return new ComponentIterator(this, keyComponent, ...components) as any;
379
+ iterator<TKey, TRelated extends any[]>(
380
+ keyComponent: ComponentClass<TKey>,
381
+ ...components: ComponentClasses<TRelated>
382
+ ) {
383
+ return new ComponentIterator(new ComponentQuery(this, keyComponent, ...components));
384
+ }
385
+
386
+ /**
387
+ * Creates a query that can be stored and reused
388
+ *
389
+ * @param keyComponent
390
+ * @param components
391
+ * @example
392
+ * const query = ecs.query(Player, Position)
393
+ *
394
+ * // get the first entry
395
+ * const [playerId, player, position] = query.firstEntry() ?? []
396
+ *
397
+ * // get the first key
398
+ * const [playerId, position] = query.firstKey() ?? []
399
+ *
400
+ * // get the first value
401
+ * const [player, position] = query.firstValue() ?? []
402
+ *
403
+ * // iterate
404
+ * for (const [playerId, player, position] of query) {
405
+ *
406
+ * }
407
+ */
408
+ query<TKey, TRelated extends any[]>(
409
+ keyComponent: ComponentClass<TKey>,
410
+ ...components: ComponentClasses<TRelated>
411
+ ) {
412
+ return new ComponentQuery(this, keyComponent, ...components)
382
413
  }
383
414
 
384
415
  /**
@@ -0,0 +1,60 @@
1
+ import type { ComponentMap } from './component-map.js';
2
+ import type { ComponentQuery } from './query.js';
3
+ import type { IteratorResult } from './types.js';
4
+
5
+ /**
6
+ * @category Iterators
7
+ * @example
8
+ * // construct an instance
9
+ * const iterator = new ComponentIterator(new ComponentQuery(entityMap, Player, Position))
10
+ *
11
+ * // iterate each component value that is related to the Player
12
+ * for(const [entityId, player, position] of iterator) { }
13
+ *
14
+ * // you can also reset the iterator back to the start
15
+ * // without having to create a new ComponentIterator instance
16
+ * iterator.reset()
17
+ * for(const [entityId, player, position] of iterator) { }
18
+ */
19
+ export class ComponentIterator<TKey, TRelated extends any[]> {
20
+ private keyMap: ComponentMap<TKey>;
21
+ private componentMaps: ComponentMap<any>[] = [];
22
+ // iteration state
23
+ private entries: MapIterator<[number, TKey]>;
24
+
25
+ constructor(query: ComponentQuery<TKey, TRelated>) {
26
+ // @ts-ignore
27
+ this.keyMap = query.keyMap
28
+ // @ts-ignore
29
+ this.componentMaps = query.componentMaps
30
+ this.entries = this.keyMap.entries();
31
+ }
32
+
33
+ /**
34
+ * gets the next iterator value
35
+ */
36
+ next(): IteratorResult<[number, TKey, ...TRelated]> {
37
+ const entry = this.entries.next();
38
+ const { value, done } = entry;
39
+ if (done) return { value: value as any, done };
40
+
41
+ const [entityId, entityValue] = value;
42
+ const results = [entityId, entityValue]
43
+ for (let i = 0; i < this.componentMaps.length; i++) {
44
+ const map = this.componentMaps[i];
45
+ results.push(map.get(entityId));
46
+ }
47
+
48
+ return { value: results as any, done: false };
49
+ }
50
+
51
+ /**
52
+ * resets the iterator back to the first entry
53
+ */
54
+ reset() {
55
+ this.entries = this.keyMap.entries();
56
+ }
57
+
58
+ [Symbol.iterator]() { return this; }
59
+
60
+ }
package/src/query.ts ADDED
@@ -0,0 +1,102 @@
1
+ import type { ComponentMap } from './component-map.js';
2
+ import type { EntityMap } from './entity-map.js';
3
+ import { ComponentIterator } from './iterator.js';
4
+ import type { ComponentClass, ComponentClasses, SingleOrArray } from './types.js';
5
+
6
+ /**
7
+ * @category Queries
8
+ * @example
9
+ * const query = ecs.query(Player, Position)
10
+ *
11
+ * // get the first entry
12
+ * const [playerId, player, position] = query.firstEntry() ?? []
13
+ *
14
+ * // get the first key
15
+ * const [playerId, position] = query.firstKey() ?? []
16
+ *
17
+ * // get the first value
18
+ * const [player, position] = query.firstValue() ?? []
19
+ *
20
+ * // iterate
21
+ * for (const [playerId, player, position] of query) {
22
+ *
23
+ * }
24
+ */
25
+ export class ComponentQuery<TKey, TRelated extends any[]> {
26
+ private keyMap: ComponentMap<TKey>
27
+ private componentMaps: ComponentMap<any>[] = []
28
+
29
+ /**
30
+ * @throwsError {@link ComponentNotRegistered} when any of specified component(s) are not registered
31
+ */
32
+ constructor(
33
+ public ecs: EntityMap,
34
+ ...components: [ComponentClass<TKey>, ...ComponentClasses<TRelated>]
35
+ ) {
36
+ this.keyMap = this.ecs.getMap(components[0])!;
37
+ for (let i = 1; i < components.length; i++) {
38
+ this.componentMaps.push(this.ecs.getMap(components[i])!)
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Returns the first entity entry
44
+ * Also returns related components specified in the query constructor
45
+ */
46
+ firstEntry(): [number, TKey, ...TRelated] | undefined;
47
+ firstEntry() {
48
+ if (this.componentMaps.length === 0) return this.keyMap.firstEntry()
49
+
50
+ const [entityId, entryValue] = this.keyMap.firstEntry() ?? []
51
+ if (entityId === undefined) return undefined;
52
+
53
+ const results: any[] = [entityId, entryValue]
54
+ for (let i = 0; i < this.componentMaps.length; i++) {
55
+ results.push(this.componentMaps[i].get(entityId));
56
+ }
57
+
58
+ return results
59
+ }
60
+
61
+ /**
62
+ * Returns the first entity id
63
+ * Also returns related components specified in the query constructor
64
+ */
65
+ firstKey(): SingleOrArray<[number, ...TRelated]> | undefined;
66
+ firstKey() {
67
+ const entityId = this.keyMap.firstKey()
68
+ if (this.componentMaps.length === 0) return entityId;
69
+ if (entityId === undefined) return undefined;
70
+
71
+ const results: any[] = [entityId]
72
+ for (let i = 0; i < this.componentMaps.length; i++) {
73
+ results.push(this.componentMaps[i].get(entityId));
74
+ }
75
+
76
+ return results
77
+ }
78
+
79
+ /**
80
+ * Returns the first value
81
+ * Also returns related components specified in the query constructor
82
+ */
83
+ firstValue(): SingleOrArray<[TKey, ...TRelated]> | undefined;
84
+ firstValue() {
85
+ if (this.componentMaps.length === 0) return this.keyMap.firstValue()
86
+
87
+ const [entityId, keyValue] = this.keyMap.firstEntry() ?? []
88
+ if (entityId === undefined) return undefined;
89
+
90
+ const results = [keyValue]
91
+ for (let i = 0; i < this.componentMaps.length; i++) {
92
+ results.push(this.componentMaps[i].get(entityId));
93
+ }
94
+
95
+ return results
96
+ }
97
+
98
+ [Symbol.iterator]() {
99
+ return new ComponentIterator(this);
100
+ }
101
+
102
+ }
package/src/types.ts CHANGED
@@ -21,8 +21,14 @@ export type ComponentClass<ComponentInstance> = new (...args: any[]) => Componen
21
21
  /**
22
22
  * Used for infering generic type spread for classes
23
23
  */
24
- export type ComponentClasses<TClasses extends Component[]> =
25
- { [Index in keyof TClasses]: TClasses[Index] }
24
+ export type ComponentClasses<T extends Component[]> =
25
+ { [Index in keyof T]: ComponentClass<T[Index]> }
26
+
27
+ export type SingleOrArray<T extends any[]> =
28
+ // return a single variadic item when only 1 item is specified
29
+ T['length'] extends 1 ? T[0]
30
+ // otherwise return an array of variadic types
31
+ : { [Index in keyof T]: T[Index] }
26
32
 
27
33
  /**
28
34
  * Used for infering generic type spread for class instances
@@ -1,37 +0,0 @@
1
- import type { EntityMap } from './entity-map.js';
2
- import type { ComponentClass, ComponentInstances, IteratorResult } from './types.js';
3
- /**
4
- * @category Iterators
5
- * @example
6
- * // construct an instance
7
- * const iterator = new ComponentIterator(entityMap, Player, Position)
8
- *
9
- * // iterate each component value that is related to the Player
10
- * for(const [entityId, player, position] of iterator) { }
11
- *
12
- * // you can also reset the iterator back to the start
13
- * // without having to create a new ComponentIterator instance
14
- * iterator.reset()
15
- * for(const [entityId, player, position] of iterator) { }
16
- */
17
- export declare class ComponentIterator<TComponentKey extends ComponentClass<any>, TComponentClasses extends ComponentClass<any>[]> {
18
- ecs: EntityMap;
19
- key: TComponentKey;
20
- private keyMap;
21
- private components;
22
- private entries;
23
- /**
24
- * {@link ComponentNotRegistered} when any of specified component(s) are not registered
25
- */
26
- constructor(ecs: EntityMap, key: TComponentKey, ...components: TComponentClasses);
27
- /**
28
- * gets the next iterator value
29
- */
30
- next(): IteratorResult<ComponentInstances<[ComponentClass<number>, TComponentKey, ...TComponentClasses]>>;
31
- /**
32
- * resets the iterator back to the first entry
33
- */
34
- reset(): void;
35
- [Symbol.iterator](): this;
36
- }
37
- //# sourceMappingURL=iterators.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"iterators.d.ts","sourceRoot":"","sources":["../../../src/iterators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAErF;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAiB,CAC5B,aAAa,SAAS,cAAc,CAAC,GAAG,CAAC,EACzC,iBAAiB,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE;IAW5B,GAAG,EAAE,SAAS;IAAS,GAAG,EAAE,aAAa;IAR5D,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,UAAU,CAAqB;IAEvC,OAAO,CAAC,OAAO,CAAsC;IAErD;;OAEG;gBACgB,GAAG,EAAE,SAAS,EAAS,GAAG,EAAE,aAAa,EAAE,GAAG,UAAU,EAAE,iBAAiB;IAM9F;;OAEG;IACH,IAAI,IAAI,cAAc,CAAC,kBAAkB,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,GAAG,iBAAiB,CAAC,CAAC,CAAC;IAczG;;OAEG;IACH,KAAK;IAIL,CAAC,MAAM,CAAC,QAAQ,CAAC;CAElB"}
package/src/iterators.ts DELETED
@@ -1,64 +0,0 @@
1
- import type { ComponentMap } from './component-map.js';
2
- import type { EntityMap } from './entity-map.js';
3
- import type { ComponentClass, ComponentInstances, IteratorResult } from './types.js';
4
-
5
- /**
6
- * @category Iterators
7
- * @example
8
- * // construct an instance
9
- * const iterator = new ComponentIterator(entityMap, Player, Position)
10
- *
11
- * // iterate each component value that is related to the Player
12
- * for(const [entityId, player, position] of iterator) { }
13
- *
14
- * // you can also reset the iterator back to the start
15
- * // without having to create a new ComponentIterator instance
16
- * iterator.reset()
17
- * for(const [entityId, player, position] of iterator) { }
18
- */
19
- export class ComponentIterator<
20
- TComponentKey extends ComponentClass<any>,
21
- TComponentClasses extends ComponentClass<any>[]
22
- > {
23
-
24
- private keyMap: ComponentMap<any>
25
- private components: ComponentMap<any>[]
26
- // iteration state
27
- private entries: MapIterator<[number, TComponentKey]>
28
-
29
- /**
30
- * {@link ComponentNotRegistered} when any of specified component(s) are not registered
31
- */
32
- constructor(public ecs: EntityMap, public key: TComponentKey, ...components: TComponentClasses) {
33
- this.keyMap = this.ecs.getMap(key)!;
34
- this.entries = this.keyMap.entries();
35
- this.components = components.map(x => this.ecs.getMap(x)!);
36
- }
37
-
38
- /**
39
- * gets the next iterator value
40
- */
41
- next(): IteratorResult<ComponentInstances<[ComponentClass<number>, TComponentKey, ...TComponentClasses]>> {
42
- const entry = this.entries.next();
43
- const { value, done } = entry;
44
- if (done) return { value: value as any, done };
45
-
46
- const [entityId, entityValue] = value;
47
- const results = [entityId, entityValue]
48
- for (const x of this.components) {
49
- results.push(x.get(entityId));
50
- }
51
-
52
- return { value: results as any, done: false };
53
- }
54
-
55
- /**
56
- * resets the iterator back to the first entry
57
- */
58
- reset() {
59
- this.entries = this.keyMap.entries();
60
- }
61
-
62
- [Symbol.iterator]() { return this; }
63
-
64
- }