@jael-ecs/core 1.0.2 → 1.0.3

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/README.md CHANGED
@@ -279,6 +279,16 @@ const count = query.entities.size();
279
279
 
280
280
  // Check if query has any entities
281
281
  const isEmpty = query.entities.size() === 0;
282
+
283
+ // Subscribe to query events
284
+ query.on('added', (entity: Entity) => {
285
+ // Entity added
286
+ })
287
+
288
+ query.on('removed', (entity: Entity) => {
289
+ // Entity added
290
+ })
291
+
282
292
  ```
283
293
 
284
294
  ### SparseSet
@@ -315,7 +325,7 @@ sparseSet.clear();
315
325
  Utility singleton class for managing time and delta time calculations.
316
326
 
317
327
  ```typescript
318
- import { Time } from "@jael/core";
328
+ import { Time } from "@jael-ecs/core";
319
329
 
320
330
  Time.start();
321
331
 
@@ -342,6 +352,11 @@ interface WorldEvents {
342
352
  updated: void;
343
353
  }
344
354
 
355
+ interface QueryEvents {
356
+ added: Entity; //Entity added to query entities
357
+ removed: Entity; //Entity removed to query entities
358
+ }
359
+
345
360
  // Listen to events
346
361
  world.on("entityCreated", (data) => {
347
362
  // Handle event
@@ -16,6 +16,7 @@ export declare class ComponentManager extends EventRegistry<ComponentManagerEven
16
16
  componentSet: Map<number, ComponentSchema>;
17
17
  world: World;
18
18
  constructor(world: World);
19
+ clearComponentSchema(entity: Entity): void;
19
20
  addComponent<K extends keyof ComponentSchema>(entity: Entity, key: K, value: ComponentSchema[K]): void;
20
21
  getComponent<K extends keyof ComponentSchema>(entity: Entity, key: K): ComponentSchema[K] | undefined;
21
22
  hasComponent<K extends keyof ComponentSchema>(entity: Entity, key: K): boolean;
package/dist/Query.d.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import { Entity } from './EntityManager';
2
+ import { default as EventRegistry } from './EventRegistry';
2
3
  import { SparseSet } from './SparseSet';
3
4
  import { default as World } from './World';
4
5
  export interface QueryConfig {
5
6
  include: string[];
6
7
  exclude: string[];
7
8
  }
8
- export declare class Query {
9
+ export interface QueryEvents {
10
+ added: Entity;
11
+ removed: Entity;
12
+ }
13
+ export declare class Query extends EventRegistry<QueryEvents> {
9
14
  config: QueryConfig;
10
15
  entityMap: SparseSet<Entity>;
11
16
  world: World;
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import { default as EventRegistry } from './EventRegistry';
2
2
  import { System, SystemManager } from './SystemManager';
3
3
  import { Entity, EntityManager, EntityManagerEvents } from './EntityManager';
4
4
  import { ComponentSchema, ComponentManager, ComponentManagerEvents } from './ComponentManager';
5
- import { Query, QueryConfig } from './Query';
5
+ import { Query, QueryConfig, QueryEvents } from './Query';
6
6
  import { SparseSet } from './SparseSet';
7
7
  import { Time, TimeEvents } from './Time';
8
8
  import { default as World, WorldEvents } from './World';
9
- export { type System, type Entity, type EntityManagerEvents, type ComponentManagerEvents, type ComponentSchema, type QueryConfig, type TimeEvents, type WorldEvents, Query, World, Time, SparseSet, EventRegistry, SystemManager, EntityManager, ComponentManager, };
9
+ export { type System, type Entity, type EntityManagerEvents, type ComponentManagerEvents, type ComponentSchema, type QueryConfig, type QueryEvents, type TimeEvents, type WorldEvents, Query, World, Time, SparseSet, EventRegistry, SystemManager, EntityManager, ComponentManager, };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class h{_listeners=new Map;on(e,t){if(this.contains(e,t))return;const s=this._listeners.get(e);s?s.add(t):this._listeners.set(e,new Set([t]))}off(e,t){if(!this.contains(e,t))return;const s=this._listeners.get(e);s&&s.delete(t)}once(e,t){const s=(i=>{t(i),this.off(e,s)});this.on(e,s)}clearEvent(e){this._listeners.get(e)&&this._listeners.get(e)?.clear()}clearAllEvents(){this._listeners.forEach(e=>e.clear()),this._listeners.clear()}contains(e,t){return this._listeners.get(e)?this._listeners.get(e).has(t):!1}emit(e,t){this._listeners.get(e)&&this._listeners.get(e)?.forEach(s=>{s(t)})}}class u{systemList=[];addSystem(e){this.systemList.push(e),e.init?.(),this.reorder()}reorder(){this.systemList.sort((e,t)=>e.priority-t.priority)}has(e){return this.systemList.indexOf(e)>0}removeSystem(e){if(!this.has(e))return;const t=this.systemList.indexOf(e);t>=0&&(this.systemList.splice(t,1),e.exit?.(),this.reorder())}}class d{denseValues=[];sparse=new Map;[Symbol.iterator](){let e=this.values.length;const t={value:void 0,done:!1};return{next:()=>(t.value=this.values[--e],t.done=e<0,t)}}get values(){return this.denseValues}first(){return this.denseValues[0]}add(e){this.has(e)||(this.denseValues.push(e),this.sparse.set(e,this.denseValues.length-1))}indexOf(e){return this.sparse.get(e)?this.sparse.get(e):-1}remove(e){if(!this.has(e))return;const t=this.sparse.get(e);this.sparse.delete(e);const s=this.denseValues[this.denseValues.length-1];s!==e&&(this.denseValues[t]=s,this.sparse.set(s,t)),this.denseValues.pop()}forEach(e){for(let t of this)e(t)}size(){return this.denseValues.length}clear(){for(let e of this)this.remove(e)}has(e){return this.sparse.has(e)}}class m{id;_world;constructor(e,t){this.id=t,this._world=e}add(e,t){this._world.addComponent(this,e,t)}remove(e){this._world.removeComponent(this,e)}has(e){return this._world.componentManager.hasComponent(this,e)}get(e){return this._world.componentManager.getComponent(this,e)}}class c extends h{entityMap=new d;nextId=0;_world;constructor(e){super(),this._world=e}get entities(){return this.entityMap}create(){const e=this.nextId++,t=new m(this._world,e);return this.entities.add(t),this.emit("create",t),t}exist(e){return this.entities.has(e)}size(){return this.entities.size()}destroy(e){return this.entities.remove(e),this.emit("destroy",e),e}}class l extends h{componentSet=new Map;world;constructor(e){super(),this.world=e,this.world.on("entityDestroyed",t=>{t&&t.entity&&this.componentSet.get(t.entity.id)&&this.componentSet.delete(t.entity.id)})}addComponent(e,t,s){const i=this.componentSet.get(e.id);i?i[t]=s:this.componentSet.set(e.id,{[t]:s}),this.emit("add",{entity:e,component:t})}getComponent(e,t){return this.hasComponent(e,t)?this.componentSet.get(e.id)[t]:void 0}hasComponent(e,t){const s=this.componentSet.get(e.id);return s?t in s:!1}removeComponent(e,t){if(!this.componentSet.get(e.id))return;const s=this.componentSet.get(e.id);s&&s[t]!==void 0&&(delete s[t],Object.keys(s).length===0&&this.componentSet.delete(e.id),this.emit("remove",{entity:e,component:t}))}}class a{config;entityMap;world;constructor(e,t){this.config=e,this.world=t,this.entityMap=new d}hasComponents(e){return this.config.include?.every(t=>e.has(t))&&this.config.exclude?.every(t=>!e.has(t))}get entities(){return this.entityMap}include(...e){return this.world.include(...e)}exclude(...e){return this.world.exclude(...e)}_checkExistingEntities(){for(let e of this.entities)this.world.exist(e)||this.entityMap.remove(e)}checkEntities(){for(let e of this.world.entities)e&&this.hasComponents(e)&&this.entityMap.add(e);this._checkExistingEntities()}static getHash(e){const t=e.include?.map(n=>n.trim()).filter(n=>n).join("_"),s=e.exclude?.map(n=>n.trim()).filter(n=>n).join("_"),i="in_"+t+"_out_"+s;let o=0;for(const n of i)o=(o<<5)-o+n.charCodeAt(0),o|=0;return o}}class p extends h{_startTime=0;_oldTime=0;_requestId=0;running=!1;delta=0;elapsed=0;constructor(){super()}_loop(){let e=0;if(this.running){const t=performance.now();e=(t-this._oldTime)/1e3,this._oldTime=t,this.elapsed+=e}this.delta=e,this.emit("update"),this._requestId=requestAnimationFrame(this._loop.bind(this))}start(){this._startTime=performance.now(),this._oldTime=this._startTime,this.elapsed=0,this.delta=0,this.running=!0,this._loop()}stop(){this.running=!1,cancelAnimationFrame(this._requestId),this._requestId=0}}let g=new p;class f extends h{entityManager;componentManager;systemManager;queries;constructor(){super(),this.entityManager=new c(this),this.componentManager=new l(this),this.systemManager=new u,this.entityManager.on("create",e=>{e&&this.emit("entityCreated",{entity:e}),this._updateQueries()}),this.entityManager.on("destroy",e=>{e&&this.emit("entityDestroyed",{entity:e}),this._updateQueries()}),this.componentManager.on("add",e=>{this.emit("componentAdded",{entity:e.entity,component:e.component}),this._updateQueries()}),this.componentManager.on("remove",e=>{this.emit("componentRemoved",{entity:e.entity,component:e.component}),this._updateQueries()}),this.queries=new Map}get entities(){return this.entityManager.entities}query(e){const t=a.getHash(e);let i=this.queries.get(t);return i||(i=new a(e,this),this.queries.set(t,i),this._updateQueries()),i}_updateQueries(){this.queries.forEach(e=>e.checkEntities())}exist(e){return this.entityManager.exist(e)}include(...e){return this.query({include:e,exclude:[]})}exclude(...e){return this.query({include:[],exclude:e})}create(){return this.entityManager.create()}destroy(e){this.entityManager.destroy(e)}addSystem(e){this.systemManager.addSystem(e)}removeSystem(e){this.systemManager.removeSystem(e)}addComponent(e,t,s){this.componentManager.addComponent(e,t,s)}removeComponent(e,t){this.componentManager.removeComponent(e,t)}update(){this.systemManager.systemList.forEach(e=>{e.update()}),this.emit("updated")}}exports.ComponentManager=l;exports.EntityManager=c;exports.EventRegistry=h;exports.Query=a;exports.SparseSet=d;exports.SystemManager=u;exports.Time=g;exports.World=f;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class o{_listeners=new Map;on(e,t){if(this.contains(e,t))return;const s=this._listeners.get(e);s?s.add(t):this._listeners.set(e,new Set([t]))}off(e,t){if(!this.contains(e,t))return;const s=this._listeners.get(e);s&&s.delete(t)}once(e,t){const s=(i=>{t(i),this.off(e,s)});this.on(e,s)}clearEvent(e){this._listeners.get(e)&&this._listeners.get(e)?.clear()}clearAllEvents(){this._listeners.forEach(e=>e.clear()),this._listeners.clear()}contains(e,t){return this._listeners.get(e)?this._listeners.get(e).has(t):!1}emit(e,t){this._listeners.get(e)&&this._listeners.get(e)?.forEach(s=>{s(t)})}}class c{systemList=[];addSystem(e){this.systemList.push(e),e.init?.(),this.reorder()}reorder(){this.systemList.sort((e,t)=>e.priority-t.priority)}has(e){return this.systemList.indexOf(e)>0}removeSystem(e){if(!this.has(e))return;const t=this.systemList.indexOf(e);t>=0&&(this.systemList.splice(t,1),e.exit?.(),this.reorder())}}class d{denseValues=[];sparse=new Map;[Symbol.iterator](){let e=this.values.length;const t={value:void 0,done:!1};return{next:()=>(t.value=this.values[--e],t.done=e<0,t)}}get values(){return this.denseValues}first(){return this.denseValues[0]}add(e){this.has(e)||(this.denseValues.push(e),this.sparse.set(e,this.denseValues.length-1))}indexOf(e){return this.sparse.get(e)?this.sparse.get(e):-1}remove(e){if(!this.has(e))return;const t=this.sparse.get(e);this.sparse.delete(e);const s=this.denseValues[this.denseValues.length-1];s!==e&&(this.denseValues[t]=s,this.sparse.set(s,t)),this.denseValues.pop()}forEach(e){for(let t of this)e(t)}size(){return this.denseValues.length}clear(){for(let e of this)this.remove(e)}has(e){return this.sparse.has(e)}}class m{id;_world;constructor(e,t){this.id=t,this._world=e}add(e,t){this._world.addComponent(this,e,t)}remove(e){this._world.removeComponent(this,e)}has(e){return this._world.componentManager.hasComponent(this,e)}get(e){return this._world.componentManager.getComponent(this,e)}}class u extends o{entityMap=new d;nextId=0;_world;constructor(e){super(),this._world=e}get entities(){return this.entityMap}create(){const e=this.nextId++,t=new m(this._world,e);return this.entities.add(t),this.emit("create",t),t}exist(e){return this.entities.has(e)}size(){return this.entities.size()}destroy(e){return this.entities.remove(e),this.emit("destroy",e),e}}class l extends o{componentSet=new Map;world;constructor(e){super(),this.world=e}clearComponentSchema(e){this.componentSet.get(e.id)&&this.componentSet.delete(e.id)}addComponent(e,t,s){const i=this.componentSet.get(e.id);i?i[t]=s:this.componentSet.set(e.id,{[t]:s}),this.emit("add",{entity:e,component:t})}getComponent(e,t){return this.hasComponent(e,t)?this.componentSet.get(e.id)[t]:void 0}hasComponent(e,t){const s=this.componentSet.get(e.id);return s?t in s:!1}removeComponent(e,t){if(!this.componentSet.get(e.id))return;const s=this.componentSet.get(e.id);s&&s[t]!==void 0&&(delete s[t],Object.keys(s).length===0&&this.componentSet.delete(e.id),this.emit("remove",{entity:e,component:t}))}}class a extends o{config;entityMap;world;constructor(e,t){super(),this.config=e,this.world=t,this.entityMap=new d}hasComponents(e){return this.config.include?.every(t=>e.has(t))&&this.config.exclude?.every(t=>!e.has(t))}get entities(){return this.entityMap}include(...e){return this.world.include(...e)}exclude(...e){return this.world.exclude(...e)}_checkExistingEntities(){for(let e of this.entities)this.world.exist(e)||(this.emit("removed",e),this.entityMap.remove(e))}checkEntities(){for(let e of this.world.entities)e&&this.hasComponents(e)&&(this.entityMap.add(e),this.emit("added",e));this._checkExistingEntities()}static getHash(e){const t=e.include?.map(n=>n.trim()).filter(n=>n).join("_"),s=e.exclude?.map(n=>n.trim()).filter(n=>n).join("_"),i="in_"+t+"_out_"+s;let h=0;for(const n of i)h=(h<<5)-h+n.charCodeAt(0),h|=0;return h}}class p extends o{_startTime=0;_oldTime=0;_requestId=0;running=!1;delta=0;elapsed=0;constructor(){super()}_loop(){let e=0;if(this.running){const t=performance.now();e=(t-this._oldTime)/1e3,this._oldTime=t,this.elapsed+=e}this.delta=e,this.emit("update"),this._requestId=requestAnimationFrame(this._loop.bind(this))}start(){this._startTime=performance.now(),this._oldTime=this._startTime,this.elapsed=0,this.delta=0,this.running=!0,this._loop()}stop(){this.running=!1,cancelAnimationFrame(this._requestId),this._requestId=0}}let g=new p;class f extends o{entityManager;componentManager;systemManager;queries;constructor(){super(),this.entityManager=new u(this),this.componentManager=new l(this),this.systemManager=new c,this.entityManager.on("create",e=>{e&&(this.emit("entityCreated",{entity:e}),this._updateQueries())}),this.entityManager.on("destroy",e=>{e&&(this.emit("entityDestroyed",{entity:e}),this._updateQueries(),this.componentManager.clearComponentSchema(e))}),this.componentManager.on("add",e=>{this.emit("componentAdded",{entity:e.entity,component:e.component}),this._updateQueries()}),this.componentManager.on("remove",e=>{this.emit("componentRemoved",{entity:e.entity,component:e.component}),this._updateQueries()}),this.queries=new Map}get entities(){return this.entityManager.entities}query(e){const t=a.getHash(e);let i=this.queries.get(t);return i||(i=new a(e,this),this.queries.set(t,i),this._updateQueries()),i}_updateQueries(){this.queries.forEach(e=>e.checkEntities())}exist(e){return this.entityManager.exist(e)}include(...e){return this.query({include:e,exclude:[]})}exclude(...e){return this.query({include:[],exclude:e})}create(){return this.entityManager.create()}destroy(e){this.entityManager.destroy(e)}addSystem(e){this.systemManager.addSystem(e)}removeSystem(e){this.systemManager.removeSystem(e)}addComponent(e,t,s){this.componentManager.addComponent(e,t,s)}removeComponent(e,t){this.componentManager.removeComponent(e,t)}update(){this.systemManager.systemList.forEach(e=>{e.update()}),this.emit("updated")}}exports.ComponentManager=l;exports.EntityManager=u;exports.EventRegistry=o;exports.Query=a;exports.SparseSet=d;exports.SystemManager=c;exports.Time=g;exports.World=f;
@@ -33,7 +33,7 @@ class h {
33
33
  });
34
34
  }
35
35
  }
36
- class u {
36
+ class c {
37
37
  systemList = [];
38
38
  addSystem(e) {
39
39
  this.systemList.push(e), e.init?.(), this.reorder();
@@ -97,7 +97,7 @@ class d {
97
97
  return this.sparse.has(e);
98
98
  }
99
99
  }
100
- class c {
100
+ class u {
101
101
  id;
102
102
  _world;
103
103
  constructor(e, t) {
@@ -146,7 +146,7 @@ class l extends h {
146
146
  return this.entityMap;
147
147
  }
148
148
  create() {
149
- const e = this.nextId++, t = new c(this._world, e);
149
+ const e = this.nextId++, t = new u(this._world, e);
150
150
  return this.entities.add(t), this.emit("create", t), t;
151
151
  }
152
152
  exist(e) {
@@ -163,9 +163,10 @@ class m extends h {
163
163
  componentSet = /* @__PURE__ */ new Map();
164
164
  world;
165
165
  constructor(e) {
166
- super(), this.world = e, this.world.on("entityDestroyed", (t) => {
167
- t && t.entity && this.componentSet.get(t.entity.id) && this.componentSet.delete(t.entity.id);
168
- });
166
+ super(), this.world = e;
167
+ }
168
+ clearComponentSchema(e) {
169
+ this.componentSet.get(e.id) && this.componentSet.delete(e.id);
169
170
  }
170
171
  addComponent(e, t, s) {
171
172
  const i = this.componentSet.get(
@@ -186,12 +187,12 @@ class m extends h {
186
187
  s && s[t] !== void 0 && (delete s[t], Object.keys(s).length === 0 && this.componentSet.delete(e.id), this.emit("remove", { entity: e, component: t }));
187
188
  }
188
189
  }
189
- class a {
190
+ class a extends h {
190
191
  config;
191
192
  entityMap;
192
193
  world;
193
194
  constructor(e, t) {
194
- this.config = e, this.world = t, this.entityMap = new d();
195
+ super(), this.config = e, this.world = t, this.entityMap = new d();
195
196
  }
196
197
  hasComponents(e) {
197
198
  return this.config.include?.every((t) => e.has(t)) && this.config.exclude?.every((t) => !e.has(t));
@@ -207,11 +208,11 @@ class a {
207
208
  }
208
209
  _checkExistingEntities() {
209
210
  for (let e of this.entities)
210
- this.world.exist(e) || this.entityMap.remove(e);
211
+ this.world.exist(e) || (this.emit("removed", e), this.entityMap.remove(e));
211
212
  }
212
213
  checkEntities() {
213
214
  for (let e of this.world.entities)
214
- e && this.hasComponents(e) && this.entityMap.add(e);
215
+ e && this.hasComponents(e) && (this.entityMap.add(e), this.emit("added", e));
215
216
  this._checkExistingEntities();
216
217
  }
217
218
  static getHash(e) {
@@ -254,10 +255,10 @@ class f extends h {
254
255
  systemManager;
255
256
  queries;
256
257
  constructor() {
257
- super(), this.entityManager = new l(this), this.componentManager = new m(this), this.systemManager = new u(), this.entityManager.on("create", (e) => {
258
- e && this.emit("entityCreated", { entity: e }), this._updateQueries();
258
+ super(), this.entityManager = new l(this), this.componentManager = new m(this), this.systemManager = new c(), this.entityManager.on("create", (e) => {
259
+ e && (this.emit("entityCreated", { entity: e }), this._updateQueries());
259
260
  }), this.entityManager.on("destroy", (e) => {
260
- e && this.emit("entityDestroyed", { entity: e }), this._updateQueries();
261
+ e && (this.emit("entityDestroyed", { entity: e }), this._updateQueries(), this.componentManager.clearComponentSchema(e));
261
262
  }), this.componentManager.on(
262
263
  "add",
263
264
  (e) => {
@@ -326,7 +327,7 @@ export {
326
327
  h as EventRegistry,
327
328
  a as Query,
328
329
  d as SparseSet,
329
- u as SystemManager,
330
+ c as SystemManager,
330
331
  g as Time,
331
332
  f as World
332
333
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jael-ecs/core",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Entity Component System library with typescript",
5
5
  "keywords": [
6
6
  "ecs",