darker-engine v7.2.1
Darker-Engine
Lightweight functional library implementation of the Entity-Component-System pattern with typescript.
Installation
Deno
Import the package with deno:
import { engine as darkerEngine } from "https://deno.land/x/darker_engine/mod.ts";
npm
Install the package with npm:
npm install darker-engine
Concepts
Action Queue System
This engine implements an action queue with three levels of priority: Priority.HIGH
, Priority.MEDIUM
, Priority.LOW
.
Actions are added to the queue and processed based on their priority.
Config
With Engine.load
config we can specify how many ticks we want per second. By default, is 60
await Engine.load({
ticksPerSecond: 40,
})
With Engine.onTick
we can sets a callback function that is run on each iteration of the loop.
The callback function receives an object with the result of the last processed action, the time (ms
) the iteration took, and the % usage of the tick.
Engine.onTick(({usage, ms, status}) => {
console.log({ms, usage, actionId: status?.id})
})
// -> { ms: 2, usage: 0.02, actionId: 1 }
With Engine.pause
you can pause the entire engine loop. All systems will call onPause
function before.
await Engine.pause()
With Engine.resume
you can start again the engine loop. All systems will call onResume
function after the loop restarts.
await Engine.resume()
Add Actions To Queue
When we use addEntity
, removeEntity
, entity.updateComponent
and entity.removeComponent
we can specify if we want to perform the action immediately or assign it a priority.
By default, they are added to the queue and assigned a medium priority (Priority.MEDIUM
)
// Action added to HIGH priority queue
await Engine.addEntity({
priority: Priority.HIGH,
entities: [exampleEntity()]
})
// Action that is executed immediately without depending on the queue
await Engine.addEntity({
force: true,
entities: [exampleEntity()]
})
Code Example
Declaration
import { engine } from "darker-engine";
export const Engine = engine<IEntities, IComponents, ComponentData>();
Engine.setSystems(...[]);
Engine.load({
ticksPerSecond: 40
});
Enums
enum EntityType {
EXAMPLE_ENTITY,
}
enum Components {
EXAMPLE_COMPONENT,
OTHER_COMPONENT
}
type ComponentData = {
[Components.EXAMPLE_COMPONENT]: {
foo: string;
},
[Components.OTHER_COMPONENT]: {
bar: number;
};
};
Entity
import { EntityTypeFunction } from "darker-engine";
const exampleEntity: EntityTypeFunction<IEntities, IComponents, ComponentData, any> = () => ({
type: Entities.EXAMPLE_ENTITY,
data: {
[Components.EXAMPLE_COMPONENT]: {
foo: "faa",
}
},
components: [Components.EXAMPLE_COMPONENT],
})
Systems
import { SystemFunction } from "darker-engine";
const exampleSystem: SystemFunction<Components> = async () => {
const onAdd = async (entityId: number) => {};
const onUpdate = async (entityId: number, component: string) => {};
const onRemove = async (entityId: number) => {};
return {
components: [],
onAdd,
onUpdate,
onRemove,
};
};
Full code
import {engine, EntityTypeFunction, SystemFunction} from "darker-engine";
enum IEntities {
EXAMPLE_ENTITY,
}
enum IComponents {
EXAMPLE_COMPONENT,
OTHER_COMPONENT,
}
type ComponentData = {
[IComponents.EXAMPLE_COMPONENT]: {
foo: string;
},
[IComponents.OTHER_COMPONENT]: {
bar: number;
};
};
export const Engine = engine<IEntities, IComponents, ComponentData>()
const exampleEntity: EntityTypeFunction<IEntities, IComponents, ComponentData, void> = () => ({
type: IEntities.EXAMPLE_ENTITY,
data: {
[IComponents.EXAMPLE_COMPONENT]: {
foo: "faa",
}
},
components: [IComponents.EXAMPLE_COMPONENT],
})
const exampleSystem: SystemFunction<IComponents> = async () => {
let interval: number
const onLoad = async () => {
console.log("welcome!");
await Engine.addEntity({
entities: [exampleEntity()]
})
interval = setInterval(() => {
const entityList = Engine.getEntityList();
const entityListByType = Engine.getEntityListByType(IEntities.EXAMPLE_ENTITY);
const entityListByComponents = Engine.getEntityListByComponents(
IComponents.EXAMPLE_COMPONENT,
);
console.log(`Entities`);
console.log(` - total: ${entityList.length}`);
console.log(` - type: ${entityListByType.length}`);
console.log(` - component: ${entityListByComponents.length}`);
}, 5000);
}
const onDestroy = async () => {
clearInterval(interval);
console.log("bye!");
}
const onAdd = async (id: number) => {
const entity = Engine.getEntity(id);
if(entity) {
await entity.updateComponent({
component: IComponents.EXAMPLE_COMPONENT,
data: {foo: 'fii2'}
})
}
}
const onUpdate = async (id: number, component?: IComponents) => {
const entity = Engine.getEntity(id);
if (!entity || component !== IComponents.EXAMPLE_COMPONENT) return;
const { foo } = entity.getComponent(IComponents.EXAMPLE_COMPONENT);
if (foo === "fii" && !entity.hasComponent(IComponents.OTHER_COMPONENT)) {
await entity.removeComponent({
component: IComponents.EXAMPLE_COMPONENT
})
}
}
const onRemove = async (entityId: number) => {
await Engine.removeEntity({ids: [entityId]})
};
const onResume = async () => {
console.log('system wake up')
}
const onPause = async () => {
console.log('system paused')
}
return {
components: [IComponents.EXAMPLE_COMPONENT],
onLoad,
onResume,
onPause,
onDestroy,
onAdd,
onUpdate,
onRemove,
}
}
await Engine.setSystems(exampleSystem);
await Engine.load({
ticksPerSecond: 2,
})
Engine.onTick(({usage, ms, status, tickCount}) => {
console.log({ ms, usage, status, tickCount})
})
19 days ago
19 days ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
9 months ago
9 months ago
9 months ago
10 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago