0.2.0 • Published 5 years ago

@muini/easy-ecs v0.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
5 years ago

Easy Entity Component System is a minimalist open-source Javascript library that helps you create games quickly. It's focused on developer happyness and performance. It has zero dependancies, is super lightweight and extensible.

Introduction

Prerequisites

Just get a simple javascript project with npm support. You can also use the build version and use it without any stack.

⚠️ Note: Very early developement, expect breaking changes.

Glossary

  • World: One class instance to rule them all.
  • Entity: It's a instantiable class that is composed of Components.
  • Component: The «data» of your entity. Never instantiated, only declarative.
  • System: Where the logic happens. A system process Entities that have a specific set of Components.
  • Addon: This is a way to extend the World.

Getting Started

Installing

Install package from npm in your project or get the build/easy-ecs.js file.

npm i @muini/easy-ecs

Usage

Creating the structure of your game is a declarative process

Component

import { Component } from '@muini/easy-ecs';
// Component
export class Position extends Component{
  static name = "Position";
  static x = 0;
  static y = 0;
}
// Component inheritence
export class Position3D extends Position{
  static name = "Position3D";
  static z = 0;
}
// Another component
export class Health extends Component{
  static name = "Health";
  static health = 0;
  static maxHealth = 0;
}

Entity

import { Entity } from '@muini/easy-ecs';
// Entity is just a list of Component classes
export class Character extends Entity {
  static components = [Position]
}
// Entity inheritence, you need to spread the parent components array
export class Hero extends Character {
  static components = [...super.components, Health]
}

System

import { System } from '@muini/easy-ecs';
// System declaration
export class CharacterMovement extends System {
  // Component list that will filter entities that have those components
  dependencies = [Position]; 
  // onUpdate Will fire every world.update (or every frame if Loop Addon is added)
  onUpdate = (entities) => { 
    // entities is filtered entities
    entities.forEach(entity => {
      entity.x += 0.1 * Time.delta; //Time is an Addon, see below
      // You can access world with this.world
      // You can query entities with 
      // - this.world.getEntitiesWithComponents([...ComponentsClass])
      // - this.world.getEntitiesOfType(Class)
      // - this.world.getEntityById(id)
    })
  };
}
// Make your own system
export class MySystem extends System {
  dependencies = [MyComponent, ...]; 
  onInit = (entities) => {};
  onUpdate = (entities) => {};
}

World & Game start example

import { World } from '@muini/easy-ecs';
import { Loop, Time, Input, Renderer, SaveSystem } from '@muini/easy-ecs/addons';

import { Character } from './your-game/entities';
import { PlayerMovement, CharacterMovement, CharacterRenderer } from './your-game/systems';

//Instantiate your world
const world = new World({
  // Add as much addon as you can to extend the world and engine
  addons: [Loop, Time, Input, Renderer, SaveSystem, ...],
  // Order of systems is the order of execution
  systems: [PlayerMovement, CharacterMovement, CharacterRenderer, ...]
});
// Instantiate an entity, first arg is a World, second is default values
const bob = new Character(world, {
  x: 10,
  y: 10,
  health: 100,
  maxHealth: 100
})

// Start the world, that's all !
world.start()

Addon

Addon is an easy way to extend the world engine. Addon will never be instantiated and all properties must be static.

Official Addons

  • 🔁 Loop: Will set a loop calling world.update(timestamp) based on requestAnimationFrame
  • ⏱️ Time: Access Time.time, Time.delta and Time.elapsed easily anywhere
  • 🕹️ Input: Access to current input, either Input.mouse position or Input.isPressed(key) to check if a specific key is pressed, or Input.keypress to get all keys pressed
  • 🖼️ Renderer: Canvas Renderer with basic access to Renderer.canvas and context Renderer.ctx
  • 💾 SaveSystem: Save & restore world state from localStorage using const id = SaveSystem.saveWorld(world, saveName) and SaveSystem.restoreWorld(world, saveName)

Custom Addon

// Example of a new addon
export class MyAddon extends Addon {
  static onInit = (world) => { /*Do stuff*/ }
  static onBeforeUpdate = (world, time) => { /*Do stuff*/ }
  static onAfterUpdate = (world, time) => { /*Do stuff*/ }
}
// Example of Time Addon
export class Time extends Addon {
  static time = 0;
  static delta = 0;
  static elapsed = 0;
  static onBeforeUpdate = (world, time) => {
    Time.delta = time - Time.time;
    Time.time = time;
    Time.elapsed += Time.delta;
  }
}

Roadmap

  • Core
  • Addons: Loop, Time, Input, Renderer(canvas), SaveSystem
  • Readme
  • Example
  • Addon: Audio
  • Documentation
  • Addon: AssetManager
  • Addon: Network

Other Addon ideas = UI (html based?), WebGL Renderer, ...

Inspired by

  • Unity - ECS approach from Unity game engine
  • ECSY - ECS approach from Mozilla team
  • MattDesl - ECS approach from MattDesl

Contributing

Feel free to open issues for questions, bugs or improvements & PR !

Authors

  • Corentin Flach - Initial work - Github

License

This project is licensed under the MIT License