Construct a new ECS instance.
The instance can be configured to defer mutating operations
assign, remove, and destroy by default by passing
{ defer: true } to the constructor.
Options to configure the ECS
True to defer mutating operations by
default, defaults to false.
Private #entityPrivate #optionsPrivate #pendingOptional component?: anyPrivate #registryPrivate #storesPrivate #recordPrivate #storeAssign a component to an entity.
Each entity can only have one component of a given type.
There are two overloads to assign
the entity to assign the component
either the component to add or the type of component to add
Optional value: Partial<T> = undefineda plain object used to assign property values to the component instance
Optional defer: boolean = ...defer this operation until the next commit. defaults to the value passed into the constructor
the assigned component instance
// component type + data
class Position { x = 0; y = 0 }
const ecs = new Ecs()
const e = ecs.create()
ecs.assign(e, Position, { x: 20, y: 30 })
// component type, no data (for 'tagging' components)
class Vulnerable { }
const ecs = new Ecs()
const e = ecs.create()
ecs.assign(e, Vulnerable)
// component instance
class Speed {
amount = 0
constructor(mode) {
this.amount = mode === 'fast' ? 10 : 1
}
}
const ecs = new Ecs()
const e = ecs.create()
ecs.assign(e, new Speed('fast'))
Commits all deferred assign, remove, and destroy operations and resets internal deferral state.
When deferring operations it is a good idea to commit all operations at the start or end of the frame. That way your view of entities and components is stable during a frame.
class Position { x=0; y=0 }
const ecs = new Ecs({ defer: true })
const e = ecs.create()
ecs.assign(e, Position, { x: 10, y: 20 })
ecs.has(e, Position) // false
ecs.get(e, Position) // null
ecs.commit()
ecs.has(e, Position) // true
ecs.get(e, Position) // Position { x:10, y:20 }
Create a fresh entity.
Even though entities are just numbers, you should only use this method to allocate them. Entities created with this method are guaranteed to be unique and valid. Don't create entities any other way.
const ecs = new Ecs()
const e = ecs.create()
ecs.isValid(e) // => true
Destroy an entity.
Optional defer: boolean = ...defer this operation until the next commit. defaults to the value passed into the constructor
const ecs = new Ecs()
const e = ecs.create()
ecs.isValid(e) // => true
ecs.destroy(e)
ecs.isValid(e) // => false
Iterate each entity that contains component matching componentTypes.
Every resulting entity is guaranteed to have a component of every type provided in `componentTypes.
Rest ...componentTypes: Constructor<any>[]the types of components to query for
a generator of all matching entities
class Gremlin {}
class Goblin {}
class Spooky { amount=0 }
const ecs = new Ecs()
for(let i=0; i<1000; i++) {
const e = ecs.create()
if(Math.random() < 0.5)
ecs.assign(e, Goblin)
else
ecs.assign(e, Gremlin)
if(Math.random() < 0.25)
ecs.assign(e, Spooky, { amount: Math.random() })
}
// iterate all gremlins
for(const e of ecs.each(Gremlin)) {
ecs.get(e, Gremlin) // guaranteed not null
if(ecs.has(e, Spooky)) // might be null, check with has
ecs.get(e, Spooky)
}
// iterate all goblins
for(const e of ecs.each(Goblin)) {
ecs.get(e, Goblin) // guaranteed not null
if(ecs.has(e, Spooky)) // might be null, check with has
ecs.get(e, Spooky)
}
// iterate all spooky goblins
for(const e of ecs.each(Spooky, Goblin)) {
ecs.get(e, Goblin) // guaranteed not null
ecs.get(e, Spooky) // guaranteed not null
}
Find an entity that has all of the given components
Only one entity is assumed to match. If there is more than one matching entity which entity is returned is undefined.
Rest ...componentTypes: Constructor<any>[]const e = ecs.create()
ecs.assign(e, Player)
ecs.find(Player) === e // true
Get a component of a given type from an entity if its been assigned
Throws an exception if the entity has not been assigned the component.
Safe to use when iterating with each and when you otherwise know
component has been assigned to entity, otherwise use has to
check for component's assignment or use tryGet to return null
rather than throw when component is missing.
the entity to get the component from
the component to get
The component instance if it was assigned to entity
class Player {}
class Position { x=0; y=0 }
class Enemy {}
const ecs = new Ecs()
const e = ecs.create()
const f = ecs.create()
ecs.assign(e, Player)
ecs.assign(e, Position, { x: 20, y: 80 })
ecs.assign(f, Enemy)
ecs.assign(f, Position, { x: 40, y: 90 })
ecs.get(e, Player) // => Player {}
ecs.get(e, Position) // => Position { x: 20, y: 80 }
ecs.get(e, Position).x // => 20
ecs.get(e, Enemy) // => throws exception
ecs.get(f, Player) // => throws exception
ecs.get(f, Position) // => Position { x: 40, y: 90 }
ecs.get(f, Position).y // => 90
ecs.get(f, Enemy) // => Enemy {}
if entity was not assigned component
Check if a component of a given type has been assigned to an entity
the entity to get the component from
the component to get
true if entity has a component assigned to it, false otherwise
class Player {}
class Position { x=0; y=0 }
class Enemy {}
const ecs = new Ecs()
const e = ecs.create()
const f = ecs.create()
ecs.assign(e, Player)
ecs.assign(e, Position, { x: 20, y: 80 })
ecs.assign(f, Enemy)
ecs.assign(f, Position, { x: 40, y: 90 })
ecs.has(e, Player) // => true
ecs.has(e, Position) // => true
ecs.has(e, Enemy) // => false
ecs.has(f, Player) // => false
ecs.has(f, Position) // => true
ecs.has(f, Enemy) // => true
Check if an entity value is still valid.
A valid entity is one that was created by this ECS instance and has not been destroyed yet.
This method is useful when you store entity values in different places in your code and need to check if they were destroyed at some point.
const ecs = new Ecs()
const e = ecs.create()
ecs.isValid(e) // true
ecs.destroy(e)
ecs.isValid(e) // false
Remove a component from an entity
Optional defer: boolean = ...defer this operation until the next commit. defaults to the value passed into the constructor
class Position { x=0; y=0 }
class InBounds {}
for(const e of ecs.each(Position, InBounds)) {
const p = ecs.get(e, Position)
if(p.x < 0 || p.x > 10 || p.y < 0 || p.y > 10)
ecs.remove(e, InBounds)
}
Get a component of a given type from an entity or null if it has not
been assigned.
Similar to get with a less convenient return type. Always safe to call.
class Player {}
class Enemy {}
const ecs = new Ecs()
const e = ecs.create()
const f = ecs.create()
ecs.assign(e, Player)
ecs.assign(f, Enemy)
ecs.tryGet(e, Player) // => Player {}
ecs.tryGet(f, Enemy) // => Enemy {}
ecs.tryGet(e, Enemy) // => null
ecs.tryGet(f, Player) // => null
Entity Component System instance