aecs
TypeScript icon, indicating that this package has built-in type declarations

0.0.28 • Public • Published

Awesome Entity Component System

An entity component system made with typescript.

Install

npm i --save aecs

Getting Started

To use the entity component system, you first must create an instance of Engine.

import { Engine } from "aecs";
const engine = new Engine();

Define your Components:

import { Component } from "aecs";

// Components can have custom constructors, but they must be able to be initialized
// with no arguments, because the engine creates the instances for you.
// Try not to save complex data types in your components
// due to the handling of references inside javascript

export class PositionComponent extends Component {
    public x: number = 0;
    public y: number = 0;
}

Create an Entity type:

import { Entity } from "aecs";

//can have a constructor but is not needed
//the type is basically only used for queries from your systems

export class PlayerEntity extends Entity {}

For the creation of your entities it makes sense to define a Prefab.

import { Prefab } from "aecs";

export class PlayerPrefab extends Prefab<PlayerEntity> { // <-- entityType needed
    private spawnX: number = 0;
    private spawnY: number = 0;

    protected init(): void {
        //code here runs only once for the creation of the prefab instance
    }

    public someSetterDefinedByYou(x: number, y: number): void {
        this.spawnX = x;
        this.spawnY = y;
    }

    public instantiate(): PlayerEntity {
        const positionComponent = new PositionComponent();
        positionComponent.x = this.spawnX;
        positionComponent.y = this.spawnY;

        return new PlayerEntity(<<<SOME_ID>>>, [positionComponent]);
    }
}

Finally a System is created to work with the entities and components

import { System } from "aecs";

//in this system we will instantiate a player and listen for keyboard inputs to move the player around

export class PlayerSystem extends System {
    private playerPrefab: PlayerPrefab;

    init(): void {
        this.playerPrefab = this.prefabManager.getPrefab<PlayerPrefab>(PlayerPrefab);
        this.playerPrefab.someSetterDefinedByYou(10, 10);
        this.ecm.instantiatePrefab(this.playerPrefab);
    }

    // we have multiple ways to query for components/entities
    run(delta: number): void {
        //query by id
        let playerEntityItem = this.ecm.getEntity<PlayerEntity>(<<<SOME_ID>>>)

        //query by entity type -> returns array
        let playerEntities = this.ecm.getEntites<PlayerEntity>(PlayerEntity);

        //query by a specific component + id
        let positionComponent = this.ecm.getComponent<PositionComponent>(PositionComponent, <<<SOME_ID>>>);

        //query all by component type -> returns array
        let positionComponents = this.ecm.getComponents<PositionComponent>(PositionComponent);

        if(some key pressed) {
            //do things with entities & components here
        }
    }
}

AECS is defined by multiple Worlds. Think of a world like a container which hold multiple prefabs & systems. So you could have for example a GameWorld and a MenuWorld etc. To get the engine running we need to define a world for our systems and prefabs to run.

import { World } from "aecs";

export interface WorldProperties {
    someValue: string;
}

export class SomeWorld extends World<WorldProperties> {
    init(): void {
        this.initPrefabs([
            new PlayerPrefab(PlayerEntity)  // needs the entity type
        ]);

        this.initSystems([
            new PlayerSystem(true)  // bool if active or not
        ]);
    }

    update(delta: number): void {
        this.callSystems(delta);    //in our loop we call all systems
    }
}

In the last step we add our created GameWorld to the engine and start it all up

engine.addWorlds([
    new SomeWorld({someValue: "someValue"})
]);
engine.setActiveWorld(SomeWorld);
engine.start(60);   // number of ticks we want to have per second

//alternative you can manually call the update loop with
//engine.update(deltaTime?: number);

Important!

When you build your project with webpack it is needed to the following option to your webpack.config.js, otherwise aecs will throw all sorts of errors during runtime!

optimization: {
    minimizer: [
        new ESBuildMinifyPlugin({
            keepNames: true
        })
    ]
},

Package Sidebar

Install

npm i aecs

Weekly Downloads

4

Version

0.0.28

License

ISC

Unpacked Size

77.4 kB

Total Files

76

Last publish

Collaborators

  • bluber.games