@ste_tisci/ecs 0.1.4 → 0.1.6

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.
@@ -1,58 +1,60 @@
1
- import type { IComponentRegistry } from './types/IComponentRegistry.js';
2
- import type { IEntityManager } from './types/IEntityManager.js';
3
-
4
- export function EntityManager<K extends string>(registry: IComponentRegistry<K>): IEntityManager<K> {
5
- let nextID: number = 0;
6
- const recycledIDs: number[] = [];
7
- const bitMasks: bigint[] = [];
8
-
9
- function exists(eid: number): boolean {
10
- const isWithinBounds = eid >= 0 && eid < nextID;
11
- const hasMask = bitMasks[eid] !== undefined;
12
-
13
- return isWithinBounds && hasMask;
14
- }
15
-
16
- function hasComponent(eid: number, name: K): boolean {
17
- if (!exists(eid)) throw new Error(`Entity ${eid} does not exist`);
18
-
19
- const cid = registry.getID(name);
20
- return (bitMasks[eid] & (1n << BigInt(cid))) !== 0n;
21
- }
22
-
23
- function create(): number {
24
- const ID = recycledIDs.length > 0 ? recycledIDs.pop()! : nextID++;
25
- bitMasks[ID] = 0n;
26
-
27
- return ID;
28
- }
29
-
30
- function remove(eid: number): void {
31
- if (!exists(eid)) throw new Error(`Entity ${eid} does not exist`);
32
-
33
- bitMasks[eid] = undefined as any;
34
- recycledIDs.push(eid);
35
- }
36
-
37
- function addComponent(eid: number, name: K): void {
38
- if (!exists(eid)) throw new Error(`Entity ${eid} does not exists`);
39
- if (hasComponent(eid, name)) throw new Error(`Entity ${eid} already has component ${name}`);
40
-
41
- const cid = registry.getID(name);
42
- bitMasks[eid] |= 1n << BigInt(cid);
43
- }
44
-
45
- function removeComponent(eid: number, name: K): void {
46
- if (!exists(eid)) throw new Error(`Entity ${eid} does not exists`);
47
- if (!hasComponent(eid, name)) throw new Error(`Entity ${eid} does not have component ${name}`);
48
-
49
- const cid = registry.getID(name);
50
- bitMasks[eid] &= ~(1n << BigInt(cid));
51
- }
52
-
53
- function getMask(eid: number): bigint {
54
- return bitMasks[eid];
55
- }
56
-
57
- return { exists, hasComponent, create, remove, addComponent, removeComponent, getMask };
58
- }
1
+ import type { IComponentRegistry } from './types/IComponentRegistry.js';
2
+ import type { IEntityManager } from './types/IEntityManager.js';
3
+
4
+ export function EntityManager<K extends string>(registry: IComponentRegistry<K>): IEntityManager<K> {
5
+ let nextID: number = 0;
6
+ const recycledIDs: number[] = [];
7
+ const bitMasks: bigint[] = [];
8
+
9
+ function exists(eid: number): boolean {
10
+ const isWithinBounds = eid >= 0 && eid < nextID;
11
+ const hasMask = bitMasks[eid] !== undefined;
12
+
13
+ return isWithinBounds && hasMask;
14
+ }
15
+
16
+ function hasComponent(eid: number, name: K): boolean {
17
+ if (!exists(eid)) throw new Error(`Entity ${eid} does not exist`);
18
+
19
+ const cid = registry.getID(name);
20
+ return (bitMasks[eid] & (1n << BigInt(cid))) !== 0n;
21
+ }
22
+
23
+ function create(): number {
24
+ const ID = recycledIDs.length > 0 ? recycledIDs.pop()! : nextID++;
25
+ bitMasks[ID] = 0n;
26
+
27
+ return ID;
28
+ }
29
+
30
+ function remove(eid: number): void {
31
+ if (!exists(eid)) throw new Error(`Entity ${eid} does not exist`);
32
+
33
+ bitMasks[eid] = undefined as any;
34
+ recycledIDs.push(eid);
35
+ }
36
+
37
+ function addComponent(eid: number, name: K): void {
38
+ if (!exists(eid)) throw new Error(`Entity ${eid} does not exists`);
39
+ if (hasComponent(eid, name)) throw new Error(`Entity ${eid} already has component ${name}`);
40
+
41
+ const cid = registry.getID(name);
42
+ bitMasks[eid] |= 1n << BigInt(cid);
43
+ }
44
+
45
+ function removeComponent(eid: number, name: K): void {
46
+ if (!exists(eid)) throw new Error(`Entity ${eid} does not exists`);
47
+ if (!hasComponent(eid, name)) throw new Error(`Entity ${eid} does not have component ${name}`);
48
+
49
+ const cid = registry.getID(name);
50
+ bitMasks[eid] &= ~(1n << BigInt(cid));
51
+ }
52
+
53
+ function getMask(eid: number): bigint {
54
+ if (!exists(eid)) throw new Error(`Entity ${eid} does not exist`);
55
+
56
+ return bitMasks[eid];
57
+ }
58
+
59
+ return { exists, hasComponent, create, remove, addComponent, removeComponent, getMask };
60
+ }
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export { ECS } from './Ecs.js';
1
+ export { ECS } from './Ecs.js';
@@ -1,29 +1,29 @@
1
- /**
2
- * Interface for managing component registration and ID mapping.
3
- * Provides a centralized registry that maps component names to unique IDs
4
- * and vice versa, used for efficient bitmask operations in the ECS.
5
- */
6
- export interface IComponentRegistry<K extends string> {
7
- /**
8
- * Registers a new component by name.
9
- * Assigns a unique incremental ID to the component if not already registered.
10
- * @param name - The name of the component to register
11
- */
12
- register: (name: K) => void;
13
-
14
- /**
15
- * Retrieves the unique ID associated with a component name.
16
- * @param name - The name of the component
17
- * @returns The unique ID assigned to the component
18
- * @throws Error if the component is not registered
19
- */
20
- getID: (name: K) => number;
21
-
22
- /**
23
- * Retrieves the component name associated with a given ID.
24
- * @param cid - The unique ID of the component
25
- * @returns The name of the component
26
- * @throws Error if the ID is not registered
27
- */
28
- getName: (cid: number) => K;
29
- }
1
+ /**
2
+ * Interface for managing component registration and ID mapping.
3
+ * Provides a centralized registry that maps component names to unique IDs
4
+ * and vice versa, used for efficient bitmask operations in the ECS.
5
+ */
6
+ export interface IComponentRegistry<K extends string> {
7
+ /**
8
+ * Registers a new component by name.
9
+ * Assigns a unique incremental ID to the component if not already registered.
10
+ * @param name - The name of the component to register
11
+ */
12
+ register: (name: K) => void;
13
+
14
+ /**
15
+ * Retrieves the unique ID associated with a component name.
16
+ * @param name - The name of the component
17
+ * @returns The unique ID assigned to the component
18
+ * @throws Error if the component is not registered
19
+ */
20
+ getID: (name: K) => number;
21
+
22
+ /**
23
+ * Retrieves the component name associated with a given ID.
24
+ * @param cid - The unique ID of the component
25
+ * @returns The name of the component
26
+ * @throws Error if the ID is not registered
27
+ */
28
+ getName: (cid: number) => K;
29
+ }
@@ -1,53 +1,53 @@
1
- import type { ComponentDataArrays } from './index.js';
2
-
3
- /**
4
- * Interface for storing and managing component data using Structure of Arrays (SoA) pattern.
5
- * Each component type has its own store that maintains entity-component associations
6
- * and stores component data in separate arrays per property for cache efficiency.
7
- * @template T - The component data type (object with properties)
8
- */
9
- export interface IComponentStore<T> {
10
- /**
11
- * Adds a component to an entity with the provided data.
12
- * Stores each property of the component in separate arrays for efficient iteration.
13
- * @param eid - The entity ID to add the component to
14
- * @param data - The component data to store
15
- * @throws Error if the entity already has this component
16
- */
17
- add: (eid: number, data: T) => void;
18
-
19
- /**
20
- * Removes a component from an entity.
21
- * Uses swap-and-pop technique to maintain dense arrays.
22
- * @param eid - The entity ID to remove the component from
23
- * @throws Error if the entity doesn't have this component
24
- */
25
- remove: (eid: number) => void;
26
-
27
- /**
28
- * Gets the index of an entity's component data in the dense arrays.
29
- * @param eid - The entity ID
30
- * @returns The index in the data arrays where this entity's component data is stored
31
- */
32
- getIndex: (eid: number) => number;
33
-
34
- /**
35
- * Returns the dense array of entity IDs that have this component.
36
- * Useful for efficient iteration over all entities with this component.
37
- * @returns Array of entity IDs
38
- */
39
- getDense: () => number[];
40
-
41
- /**
42
- * Returns the component data arrays organized by property.
43
- * Each property of the component type has its own array.
44
- * @returns Object mapping property names to their value arrays
45
- */
46
- getData: () => ComponentDataArrays<T>;
47
-
48
- /**
49
- * Returns the number of entities that have this component.
50
- * @returns The count of entities with this component
51
- */
52
- getSize: () => number;
53
- }
1
+ import type { ComponentDataArrays } from './index.js';
2
+
3
+ /**
4
+ * Interface for storing and managing component data using Structure of Arrays (SoA) pattern.
5
+ * Each component type has its own store that maintains entity-component associations
6
+ * and stores component data in separate arrays per property for cache efficiency.
7
+ * @template T - The component data type (object with properties)
8
+ */
9
+ export interface IComponentStore<T> {
10
+ /**
11
+ * Adds a component to an entity with the provided data.
12
+ * Stores each property of the component in separate arrays for efficient iteration.
13
+ * @param eid - The entity ID to add the component to
14
+ * @param data - The component data to store
15
+ * @throws Error if the entity already has this component
16
+ */
17
+ add: (eid: number, data: T) => void;
18
+
19
+ /**
20
+ * Removes a component from an entity.
21
+ * Uses swap-and-pop technique to maintain dense arrays.
22
+ * @param eid - The entity ID to remove the component from
23
+ * @throws Error if the entity doesn't have this component
24
+ */
25
+ remove: (eid: number) => void;
26
+
27
+ /**
28
+ * Gets the index of an entity's component data in the dense arrays.
29
+ * @param eid - The entity ID
30
+ * @returns The index in the data arrays where this entity's component data is stored
31
+ */
32
+ getIndex: (eid: number) => number;
33
+
34
+ /**
35
+ * Returns the dense array of entity IDs that have this component.
36
+ * Useful for efficient iteration over all entities with this component.
37
+ * @returns Array of entity IDs
38
+ */
39
+ getDense: () => number[];
40
+
41
+ /**
42
+ * Returns the component data arrays organized by property.
43
+ * Each property of the component type has its own array.
44
+ * @returns Object mapping property names to their value arrays
45
+ */
46
+ getData: () => ComponentDataArrays<T>;
47
+
48
+ /**
49
+ * Returns the number of entities that have this component.
50
+ * @returns The count of entities with this component
51
+ */
52
+ getSize: () => number;
53
+ }
@@ -1,63 +1,64 @@
1
- import type { QueryResult, StoreDataMap } from './index.js';
2
-
3
- /**
4
- * Interface for the main ECS registry.
5
- * Provides high-level API for entity-component management,
6
- * coordinating between EntityManager and ComponentStores.
7
- * @template T - Record type defining all component types in the ECS
8
- */
9
- export interface IECS<T> {
10
- /**
11
- * Initializes the ECS with component definitions.
12
- * Registers all components and creates their corresponding stores.
13
- * Must be called before any other operations.
14
- * @param names -component names
15
- */
16
- defineComponents<K extends readonly (keyof T)[]>(...names: K): void;
17
-
18
- /**
19
- * Creates a new entity in the ECS.
20
- * @returns The ID of the newly created entity
21
- */
22
- createEntity: () => number;
23
-
24
- /**
25
- * Completely removes an entity and all its components from the ECS.
26
- * Cleans up all component data and entity records.
27
- * @param eid - The entity ID to destroy
28
- */
29
- destroyEntity: (eid: number) => void;
30
-
31
- /**
32
- * Adds a component to an entity with the provided data.
33
- * Updates both the entity's bitmask and the component store.
34
- * @template K - The component name type (key of T)
35
- * @param eid - The entity ID
36
- * @param name - The component name
37
- * @param data - The component data to store
38
- */
39
- addComponent: <K extends keyof T>(eid: number, name: K, data: T[K]) => void;
40
-
41
- /**
42
- * Removes a component from an entity.
43
- * Updates both the entity's bitmask and the component store.
44
- * @template K - The component name type (key of T)
45
- * @param eid - The entity ID
46
- * @param name - The component name
47
- */
48
- removeComponent: <K extends keyof T>(eid: number, name: K) => void;
49
-
50
- /**
51
- * Retrieves all entities that contain the specified set of components.
52
- * Performs a filtered search across component stores and yields each matching entity.
53
- * The returned generator allows efficient iteration without allocating large arrays.
54
- *
55
- * @template C - Array of component names to query for
56
- * @param components - List of component names that the entity must include
57
- * @returns A generator that yields an object for each matching entity,
58
- * containing the entity ID and the related component data
59
- */
60
- query: <C extends (keyof T)[]>(...componentName: C) => Generator<QueryResult<T, C>>;
61
-
62
- components: StoreDataMap<T>;
63
- }
1
+ import type { QueryResult, StoreDataMap } from './index.js';
2
+
3
+ /**
4
+ * Interface for the main ECS registry.
5
+ * Provides high-level API for entity-component management,
6
+ * coordinating between EntityManager and ComponentStores.
7
+ * @template T - Record type defining all component types in the ECS
8
+ */
9
+ export interface IECS<T> {
10
+ /**
11
+ * Initializes the ECS with component definitions.
12
+ * Registers all components and creates their corresponding stores.
13
+ * Must be called before any other operations.
14
+ * @param names -component names
15
+ * @throws Error if a component name is already defined
16
+ */
17
+ defineComponents<K extends readonly (keyof T)[]>(...names: K): void;
18
+
19
+ /**
20
+ * Creates a new entity in the ECS.
21
+ * @returns The ID of the newly created entity
22
+ */
23
+ createEntity: () => number;
24
+
25
+ /**
26
+ * Completely removes an entity and all its components from the ECS.
27
+ * Cleans up all component data and entity records.
28
+ * @param eid - The entity ID to destroy
29
+ */
30
+ destroyEntity: (eid: number) => void;
31
+
32
+ /**
33
+ * Adds a component to an entity with the provided data.
34
+ * Updates both the entity's bitmask and the component store.
35
+ * @template K - The component name type (key of T)
36
+ * @param eid - The entity ID
37
+ * @param name - The component name
38
+ * @param data - The component data to store
39
+ */
40
+ addComponent: <K extends keyof T>(eid: number, name: K, data: T[K]) => void;
41
+
42
+ /**
43
+ * Removes a component from an entity.
44
+ * Updates both the entity's bitmask and the component store.
45
+ * @template K - The component name type (key of T)
46
+ * @param eid - The entity ID
47
+ * @param name - The component name
48
+ */
49
+ removeComponent: <K extends keyof T>(eid: number, name: K) => void;
50
+
51
+ /**
52
+ * Retrieves all entities that contain the specified set of components.
53
+ * Performs a filtered search across component stores and yields each matching entity.
54
+ * The returned generator allows efficient iteration without allocating large arrays.
55
+ *
56
+ * @template C - Array of component names to query for
57
+ * @param components - List of component names that the entity must include
58
+ * @returns A generator that yields an object for each matching entity,
59
+ * containing the entity ID and the related component data
60
+ */
61
+ query: <C extends (keyof T)[]>(...componentName: C) => Generator<QueryResult<C>>;
62
+
63
+ components: StoreDataMap<T>;
64
+ }
@@ -1,64 +1,65 @@
1
- /**
2
- * Interface for managing entities and their component associations.
3
- * Uses bitmasks to efficiently track which components each entity has,
4
- * enabling fast component checks and queries.
5
- */
6
- export interface IEntityManager<K extends string> {
7
- /**
8
- * Checks if an entity exists in the system.
9
- * @param eid - The entity ID to check
10
- * @returns True if the entity exists, false otherwise
11
- */
12
- exists: (eid: number) => boolean;
13
-
14
- /**
15
- * Checks if an entity has a specific component.
16
- * Uses bitwise operations on the entity's bitmask for fast lookups.
17
- * @param eid - The entity ID
18
- * @param name - The component name
19
- * @returns True if the entity has the component, false otherwise
20
- */
21
- hasComponent: (eid: number, name: K) => boolean;
22
-
23
- /**
24
- * Creates a new entity.
25
- * Recycles entity IDs when possible, otherwise assigns a new incremental ID.
26
- * @returns The ID of the newly created entity
27
- */
28
- create: () => number;
29
-
30
- /**
31
- * Removes an entity from the system.
32
- * Marks the entity ID for recycling.
33
- * @param eid - The entity ID to remove
34
- * @throws Error if the entity doesn't exist
35
- */
36
- remove: (eid: number) => void;
37
-
38
- /**
39
- * Adds a component flag to an entity's bitmask.
40
- * Updates the entity's bitmask to indicate it has the specified component.
41
- * @param eid - The entity ID
42
- * @param name - The component name
43
- * @throws Error if the entity doesn't exist or already has the component
44
- */
45
- addComponent: (eid: number, name: K) => void;
46
-
47
- /**
48
- * Removes a component flag from an entity's bitmask.
49
- * Updates the entity's bitmask to indicate it no longer has the specified component.
50
- * @param eid - The entity ID
51
- * @param name - The component name
52
- * @throws Error if the entity doesn't exist
53
- */
54
- removeComponent: (eid: number, name: K) => void;
55
-
56
- /**
57
- * Retrieves the complete bitmask for an entity.
58
- * The bitmask represents all components the entity has,
59
- * with each bit corresponding to a component ID.
60
- * @param eid - The entity ID
61
- * @returns The entity's component bitmask
62
- */
63
- getMask: (eid: number) => bigint;
64
- }
1
+ /**
2
+ * Interface for managing entities and their component associations.
3
+ * Uses bitmasks to efficiently track which components each entity has,
4
+ * enabling fast component checks and queries.
5
+ */
6
+ export interface IEntityManager<K extends string> {
7
+ /**
8
+ * Checks if an entity exists in the system.
9
+ * @param eid - The entity ID to check
10
+ * @returns True if the entity exists, false otherwise
11
+ */
12
+ exists: (eid: number) => boolean;
13
+
14
+ /**
15
+ * Checks if an entity has a specific component.
16
+ * Uses bitwise operations on the entity's bitmask for fast lookups.
17
+ * @param eid - The entity ID
18
+ * @param name - The component name
19
+ * @returns True if the entity has the component, false otherwise
20
+ */
21
+ hasComponent: (eid: number, name: K) => boolean;
22
+
23
+ /**
24
+ * Creates a new entity.
25
+ * Recycles entity IDs when possible, otherwise assigns a new incremental ID.
26
+ * @returns The ID of the newly created entity
27
+ */
28
+ create: () => number;
29
+
30
+ /**
31
+ * Removes an entity from the system.
32
+ * Marks the entity ID for recycling.
33
+ * @param eid - The entity ID to remove
34
+ * @throws Error if the entity doesn't exist
35
+ */
36
+ remove: (eid: number) => void;
37
+
38
+ /**
39
+ * Adds a component flag to an entity's bitmask.
40
+ * Updates the entity's bitmask to indicate it has the specified component.
41
+ * @param eid - The entity ID
42
+ * @param name - The component name
43
+ * @throws Error if the entity doesn't exist or already has the component
44
+ */
45
+ addComponent: (eid: number, name: K) => void;
46
+
47
+ /**
48
+ * Removes a component flag from an entity's bitmask.
49
+ * Updates the entity's bitmask to indicate it no longer has the specified component.
50
+ * @param eid - The entity ID
51
+ * @param name - The component name
52
+ * @throws Error if the entity doesn't exist
53
+ */
54
+ removeComponent: (eid: number, name: K) => void;
55
+
56
+ /**
57
+ * Retrieves the complete bitmask for an entity.
58
+ * The bitmask represents all components the entity has,
59
+ * with each bit corresponding to a component ID.
60
+ * @param eid - The entity ID
61
+ * @returns The entity's component bitmask
62
+ * @throws Error if the entity doesn't exist
63
+ */
64
+ getMask: (eid: number) => bigint;
65
+ }
@@ -1,49 +1,49 @@
1
- /**
2
- * Interface used for fast entity lookups, insertion and removal.
3
- *
4
- * Maintain two parallel arrays:
5
- *
6
- * - sparse: a direct lookup table that maps an entity ID (eid) to its index in the dense array.
7
- * - dense: a compact array that stores all active entity IDs contiguously.
8
- */
9
- export interface ISparseSet {
10
- /**
11
- * Check if an entity ID exists in the set
12
- * @param eid The entity ID to check
13
- * @returns True if the entity ID exists, false otherwise
14
- */
15
- has: (eid: number) => boolean;
16
-
17
- /**
18
- * Add the entity ID to the set
19
- * @param eid The entity ID to add
20
- * @thows Error if the entity ID is already been added
21
- */
22
- add: (eid: number) => void;
23
-
24
- /**
25
- * Remove an Entity ID from the set
26
- * @param eid The entity ID to remove
27
- * @throws Error if the ID does not exists in the set
28
- */
29
- remove: (eid: number) => void;
30
-
31
- /**
32
- * Retrive the index of the entity ID in the set
33
- * @param eid The entity ID
34
- * @returns The index corresponding to an entity ID in the set
35
- */
36
- getIndex: (eid: number) => number;
37
-
38
- /**
39
- * Retrive the full dense array that contain all the entity IDs of the set
40
- * @returns an Array with all the current entity IDs
41
- */
42
- getDense: () => number[];
43
-
44
- /**
45
- * Retrive the size representing the number of active entities in the set.
46
- * @returns The current size of the Dense array
47
- */
48
- getSize: () => number;
49
- }
1
+ /**
2
+ * Interface used for fast entity lookups, insertion and removal.
3
+ *
4
+ * Maintain two parallel arrays:
5
+ *
6
+ * - sparse: a direct lookup table that maps an entity ID (eid) to its index in the dense array.
7
+ * - dense: a compact array that stores all active entity IDs contiguously.
8
+ */
9
+ export interface ISparseSet {
10
+ /**
11
+ * Check if an entity ID exists in the set
12
+ * @param eid The entity ID to check
13
+ * @returns True if the entity ID exists, false otherwise
14
+ */
15
+ has: (eid: number) => boolean;
16
+
17
+ /**
18
+ * Add the entity ID to the set
19
+ * @param eid The entity ID to add
20
+ * @thows Error if the entity ID is already been added
21
+ */
22
+ add: (eid: number) => void;
23
+
24
+ /**
25
+ * Remove an Entity ID from the set
26
+ * @param eid The entity ID to remove
27
+ * @throws Error if the ID does not exists in the set
28
+ */
29
+ remove: (eid: number) => void;
30
+
31
+ /**
32
+ * Retrive the index of the entity ID in the set
33
+ * @param eid The entity ID
34
+ * @returns The index corresponding to an entity ID in the set
35
+ */
36
+ getIndex: (eid: number) => number;
37
+
38
+ /**
39
+ * Retrive the full dense array that contain all the entity IDs of the set
40
+ * @returns an Array with all the current entity IDs
41
+ */
42
+ getDense: () => number[];
43
+
44
+ /**
45
+ * Retrive the size representing the number of active entities in the set.
46
+ * @returns The current size of the Dense array
47
+ */
48
+ getSize: () => number;
49
+ }