moonoom
v0.0.7
Published
elastic entity component system
Downloads
6
Maintainers
Readme
Usage: see demo.js file (const {Engine, Entity, Query} = require('moonoom')
)
CDN: https://unpkg.com/moonoom (const {Engine, Entity, Query} = moonoom
)
Design
data / entities
- shorthand component access:
entity.component.property
,player.health.value
- can have many of one component:
entity.component$[2].property
,player.debuff$[2].type
- components can have components:
entity.component.component2.property
,player.arm.equipment.armour
systems / engine
- systems are added once:
engine.add('systems', ...yourSystems.map(s=> (...args)=>s.update(args))
- systems are categorized by name, so systems can be run at differing intervals, for example
logic
orrender
loops being separate:engine.update('render', renderer)
- systems added function should expect the first parameter to be the
engine
and subsequent to be parameters sent in at the update call:(engine, renderer){}
for the above call for example
query
- search with AND and/or OR
- even depth arrays (starting at 0) are AND queries, odd are OR
- example:
['hat', ['pants', 'shorts'], 'shirt']
= get anyone wearing hat, shirt, and (pants or shorts) - can exclude found entities by the same logic
- can use wildcard
*
for component of any name, example if you want all entities that have armour on a body part:body.*.armour
- can use wildcard
**
for zero or more components of any name, example if you want all entities that have anything of steel:**.steel
example, system has entity.arm.armour.steel
engine.get('arm.armour') //gets all entities that have armored arm
engine.get('*.armour') //gets all entities that have something armoured
engine.get('**.steel') //gets all entities that have anything of steel
engine.search(['*.armour'], ['*.armour.steel'])
//gets all entities that have something armoured, but the armour isn't steel
API
Component
Any class instanced object. Will be named/referenced as its constructor name, in camelCase. Your original instance will be wrapped in a proxy, so ===
won't work unless you access the component off an entity first.
class Position{
constructor(x, y){
this.x = x
this.y = y
}
}
Entity
Bag of components and some convenience methods.
create(...componentsOrArray)
...componentsOrArray
any variable number of instanced Component, or arrays of instanced Components. Use arrays if you want the first component in the array to have all the subsequent components.- returns Entity instance
const entity = Entity.create(
new Position(0, 0),
[new Body(), new Torso(), new Arm(), new Arm(), new Leg(), new Leg(), new Head()]
[new Bag(),
[new Sword(), new Steel()]
]
)
wrap(base, ...components)
base
object will have all the Component attached to it. Equivalent to the arrays increate
, but only makes one entity. Used for making one component have a set of other components.- returns Entity instance
collideds.forEach(collided=> entity.add(Entity.wrap(new Collided(), collided)))
//searchable by engine.get(collided.entity.point), if collided object had a point component
attach(engine)
- attaches entity to the given Engine, must be done for an entity to "exist". Cannot attach to multiple engines.
- returns the Entity instance
dettach()
- dettaches entity from engine, if it had one
- returns true or false if it had an engine to dettach from
add(...components)
- adds components to this entity & its engine (if exists)
...components
any variable number of instanced Component- returns Entity instance wrapped Components, with a proxy around them. Can use this for
===
.
remove(...componentsOrNames)
- removes components from this entity & its engine (if it exists)
...componentsOrNames
any variable number of instanced Component or their camelCase names- if instance is given, removes strict equal match
- if name is given, removes first component with the name
has(componentQuery)
componentQuery
Component camelCase names, but also accepts.
for separator,*
for one component of any name, and**
for zero or more components. Example:body.arm.*.steel
- return boolean true or false if exists on this entity
shorthand usage/proxy
const entity = Entity.create(
new Position(0, 0),
new Velocity(1, 1),
new Velocity(1, 2),
new Velocity(2, 2)
)
entity.position // {x: 0, y: 0}
entity.velocity // {x: 1, y: 1} // gets first velocity
entity.velocity$ // [{x: 1, y: 1}, {x: 1, y: 2}, {x: 2, y: 2}]
entity.position$ // [{x: 0, y: 0}]
delete entity.velocity // deletes first velocity
entity.velocity$ // [{x: 1, y: 2}, {x: 2, y: 2}]
delete entity.velocity$ // deletes all velocity
entity.velocity$ // []
entity.velocity // undefined
//you can also shorthand wrap components
entity.add(new Head())
entity.head.add(new Helmet()) //components after being added are essentially entities
//or entity.add(new Head())[0].add(new Helmet())
Engine
Bag of searchable entities & categorized systems.
add(category, ...systems)
category
name of systems. Can only be added once....systems
any variable number of functions that want to be called every update of this engine, receivingengine, ...args
update(category, ...args)
category
name of systems to call...args
anything you want to propagate to systems
get(...componentQueries)
...componentQueries
any variable number of Component camelCase names, but also accepts.
for separator,*
for one component of any name, and**
for zero or more components. Example:engine.get('body', 'velocity', 'body.legs', '*.jets')
- search with AND and/or OR
- even depth arrays (starting at 0) are AND queries, odd are OR
- example:
['hat', ['pants', 'shorts'], 'shirt']
: get anyone wearing hat, shirt, and (pants or shorts) - returns array of Entity
search(include, exclude)
- like query but one use
query(query)
create(...componentsOrArrays)
- shorthand for
Entity.create(...componentsOrArrays).attach(engine)
Query
constructor([include], [exclude])
include
optional, if omitted will get all entites. Component queries: any variable number of Component camelCase names, but also accepts.
for separator,*
for one component of any name, and**
for zero or more components. Example:new Query(['body', 'velocity', 'body.legs', '*.jets'])
- search with AND and/or OR
- even depth arrays (starting at 0) are AND queries, odd are OR
- example:
['hat', ['pants', 'shorts'], 'shirt']
: get anyone wearing hat, shirt, and (pants or shorts) exclude
optional. Same as include but excludes the matches
search(engine)