fimbrethil is a ECS (Entity-Component-System) for javascript written in Typescript with no dependencies.
Components are pure data containers and should not contain any logic.
The logic should be put into systems.
When adding a component to an entity, all properties can always be set with as an optional parameter which is Partial<Component>
.
Behind the scenes Components are stored in groups called Archetypes
.
There is one archetype for every permutation of component groups. However, A,B,C
and C,B,A
are the same archetype.
class Transform extends Component {
x: number = 0;
y: number = 0;
}
registerComponent(Transform);
class Velocity extends Component {
x: number = 0;
y: number = 0;
}
registerComponent(Velocity);
Systems are highorder functions, returning the ticker method. There are two kinds of systems. Tickers
and Renders
.
Tickers are designed to run at a fixed interval, such as 30 times per second.
function mover(world: IWorld) {
const componentTypes = Archetype.create(Transform, Velocity);
return (timestep: number) => {
world.query((transform, velocity) => {
transform.x += velocity.x * timestep;
transform.y += velocity.y * timestep;
}, componentTypes);
};
}
world.add(mover);
Renders are designed to run freely at the refresh rate of the monitor, for instance, such as 60fps or 144fps. They can also accept a interpolation parameter. Which can be used to interpolate frames if needed. This is optional however.
interface IRenderOptions {
renderer: Renderer;
};
function renderer(world: IWorld, options: IRenderOptions) {
const componentTypes = Archetype.create(Transform, Sprite);
return (deltatime: number, interpolation?: number) => {
world.query((transform, sprite) => {
renderer.render(sprite, transform);
}, componentTypes);
};
}
// pass an imaginary renderer to the system.
world.addRender(render, {renderer: new Renderer()});
Entities are just a single number
identifyin the entity.
They are nothing else. Entities are also used to refer to children or other similar entities which share a relation to an entity.
const id = world.createEntity()
.with(Transform)
.with(Velocity, {
x: 100,
y: 150
})
.build();
entities can also hold child entities child can for instance, inherit position and similar.
const id = world.createEntity()
.with(Transform)
.withChild(child => child
.with(Transform)
.with(Sound, {file: "boom.wav"})
.build()
).build();
For further examples, see the example directory.
examples/simple.js
- full example with minimum amount of logic.
examples/canvas.html
- canvas renderer, spawner system and killer system. Also gravity and mover system that affects position.