Skip to content

Entity Component System ​

Besides regular components, Bare includes miniplex, a small Entity Component System. GameObjects are the entities and plain fields are the components. Systems are loops over queries.

This is mostly a way to organize code: logic lives in systems that work on every object with certain fields.

ts
import { GameObject, Scene, World } from 'bare-engine';

export class Enemy extends GameObject
{
    health = 10;
    poisoned: true | undefined;

    OnAwake()
    {
        // Reset custom fields when this object is reused from its pool.
        this.health = 10;
        delete this.poisoned;
    }

    OnRemoved()
    {
        (this.scene as EcsGame).world.remove(this);
    }
}

export class EcsGame extends Scene
{
    readonly world = new World<Enemy>();
    readonly poisoned = this.world.with('health', 'poisoned');

    OnAwake()
    {
        bare.AddClass(Enemy);
    }

    OnStart()
    {
        const enemy = this.AddGameObject<Enemy>(Enemy);
        this.world.add(enemy);
        this.world.addComponent(enemy, 'poisoned', true);
    }

    OnUpdate(deltaTime: number)
    {
        for (const enemy of this.poisoned)
            enemy.health -= deltaTime;
    }

    OnClear()
    {
        // Also release any entities that weren't attached to the scene.
        for (const enemy of [...this.world])
            this.world.remove(enemy);
    }
}

To run this as your game, put it in src/game.ts, import StartBare from bare-engine, and add StartBare(EcsGame) at the end. This example demonstrates query membership; its empty enemy has no visible sprite.

OnRemoved removes the enemy from all queries, and OnClear releases remaining world entries. See pooled objects for why fields are reset in OnAwake.

world.removeComponent(obj, 'poisoned') removes a field, and the object leaves every query that needs it. query.onEntityAdded.subscribe(...) runs code when an object starts matching.

Example: the Showcase's ECS demo.

Bare Engine is open source under the MIT license.