1.1.3 • Published 2 years ago

square-ecs v1.1.3

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

Square Banner

Square

An Entity Component System(ECS) Based Game Framework

Installation

NPM

npm i square-ecs

CDN

import { Application } from 'https://unpkg.com/square-ecs@latest';

// your code

Example

app.js

import { Application } from "square-ecs";
import { InputSystem, RenderingSystem, ShapeRenderer, GravitySystem, MovementSystem } from "./src/systems.js";
import { BoxShapeComponent, VectorComponent } from "./src/components.js";

const app = new Application({
    data: {
        config: {
            canvas: {
                width: 400,
                height: 400,
            }
        },
        state: {
            score: 0,
            loading: true
        }
    },
    systems: [
        RenderingSystem, 
        ShapeRenderer, 
        InputSystem, 
        GravitySystem,
        MovementSystem
    ]
});

app.on("init", app => {
    const player = app.entityPool.getEntity();

    player.tag("visible")
          .tag("controllable")
          .tag("player")
          .attach("position", new VectorComponent(20, 20))
          .attach("shape", new BoxShapeComponent(32, 32))
          .attach("speed", 100)
          .attach("jumpforce", 500)
          .attach("velocity", new VectorComponent);

    app.add(player);
});

app.start();

systems.js

import { RenderableQuery, KinematicBodyQuery } from "./queries.js";

export function RenderingSystem(app) {
    const canvas = document.createElement("canvas");
    canvas.width = app.data.config.canvas.width;
    canvas.height = app.data.config.canvas.height;
    canvas.style.background = "#000";

    const context = canvas.getContext("2d");

    app.on("init", () => {
      document.body.appendChild(canvas);
    });

    app.on("update", () => {
        context.clearRect(0, 0, canvas.width, canvas.height);
        app.emit("render", context, canvas);
    });
};

export function InputSystem(app) {
    app.data.state.keyboard = {};

    const handleKey = ({ key, type }) => {
        app.data.state.keyboard[key === " " ? "Spacebar" : key] = type === "keydown";
    };

    window.addEventListener("keydown", handleKey);
    window.addEventListener("keyup", handleKey);
}

export function MovementSystem(app) {
    app.on("update", dt => {
        const [player] = app.query("controllable");
        if(!player.tags.has("jumping") && app.data.state.keyboard.Spacebar) {
            player.velocity.y -= player.jumpforce * dt;
        }
    });
}

export function ShapeRenderer(app) {
    app.on("render", ctx => {
        const entities = app.query(RenderableQuery);

        entities.forEach(entity => {
            ctx.fillStyle = '#fff';
            ctx.fillRect(entity.position.x, entity.position.y, entity.shape.width, entity.shape.height);
        });
    });
}

export function GravitySystem(app) {
    app.on("update", dt => {
        const entities = app.query(KinematicBodyQuery);
        entities.forEach(entity => {
            entity.position.y += entity.velocity.y;
            
            if(entity.position.y < 200) {
                entity.tag("jumping");
                entity.velocity.y += 5 * GRAVITY_CONSTANT * dt;
            } else {
                entity.untag("jumping");
                entity.velocity.y = 0;
            }
        });
    });
}

GravitySystem.GRAVITY_CONSTANT = 6.5;

queries.js

export const RenderableQuery = ['@position', '@shape', 'visible'];

export const KinematicBodyQuery = ['@position', '@shape', '@velocity'];

components.js

export class BoxShapeComponent {
    constructor(width, height) {
        this.type = "box";
        this.width = width;
        this.height = height;
    }
}

export class VectorComponent {
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }
}
1.1.3

2 years ago

1.1.2

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago