Skip to content

ericlathrop/entity-component-system

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

95 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

entity-component-system

An implementation of the Entity Component System (ECS) pattern used commonly in video games.

ECS is a way of organizing a system using composition instead of inheritance. It allows you to turn behaviors on and off by adding and removing components to entities.

This module manages the running of a list of "systems" over a collection of entities.

  • An "entity" is a logical object in a game.
  • A "component" is a chunk of data attached to an entity.
  • A "system" is a function that runs on all entities with specific components.

The only way to make changes to an entity is to create/edit/delete components attached to it.

Example

This is an example game loop:

var EntityComponentSystem = require("entity-component-system").EntityComponentSystem;
var EntityPool = require("entity-component-system").EntityPool;

var ecs = new EntityComponentSystem();

function drawBackground(entities, elapsed) { /* ... */ }
ecs.add(drawBackground);

function drawEntity(entity, elapsed) { /* ... */ }
ecs.addEach(drawEntity, "sprite"); // only run on entities with a "sprite" component

var entities = new EntityPool();
function spriteFactory() { return { "image": null }; }
entities.registerComponent("sprite", spriteFactory);
entities.load(/* some JSON */);

var lastTime = -1;
var render = function(time) {
  if (this.lastTime === -1) {
    this.lastTime = time;
  }
  var elapsed = time - this.lastTime;
  this.lastTime = time;

  ecs.run(entities, elapsed);
  window.requestAnimationFrame(render);
};
window.requestAnimationFrame(render);

EntityComponentSystem

An EntityComponentSystem holds the systems (code) and allows you to run them on the entities inside an EntityPool.

add(system)

Adds a "system" function to the ECS so it will be called once every time run is called.

  • system is a function that operates on all entities. system has the format:

    function mySystem(entityPool, elapsedTime) { /* ... */ }
    • entityPool is the EntityPool of entities to operate on.
    • elapsedTime is the elapsed time since the last call to run.

addEach(system, search)

Adds a "system" function to the ECS so it will be called once for each entity returned from EntityPool.find(search) in the EntityPool passed to run.

  • system is a function that operates on a single entity matching search. system has the format:

    function mySystem(entityId, elapsedTime) { /* ... */ }
    • entityId is the id of an entity to operate on.
    • elapsedTime is the elapsed time since the last call to run.
  • search is the name of a search that was previously registered with registerSearch. system is invoked once for every entity in the results of search.

run(entityPool, elapsedTime)

Invokes all systems in the order they were added to the EntityComponentSystem.

  • entityPool is the collection of entities to operate on.
  • elapsedTime is the time passed since you last called run.

runs()

Returns the number of times run was called.

timings()

Returns an array of each system's name and time it ran in milliseconds. The system names are gathered from the names of functions passed to add and addEach. An example return value:

{
  "drawBackground": 0.02,
  "drawEntity": 5.00
}

resetTimings()

Resets the timing information and number of runs back to zero.

EntityPool

An EntityPool holds the entities and components for an EntityComponentSystem. EntityPool provides ways to add, remove, modify, and search for entities. EntityPool also has hooks where you can provide callbacks to be notified of changes.

EntityPool also implements the Object Pool pattern to reduce stuttering caused by garbage collection.

create()

Creates a new entity, and returns the entity's id.

var player = entities.create(); // => 1

destroy(id)

Removes all the components for an entity, and deletes the entity. The onRemoveComponent callbacks are fired for each component that is removed.

  • id is the id of the entity to destroy.
entities.destroy(player);

registerComponent(component, factory, reset, size)

Registers a component type.

  • component is the name of the component to register.

  • factory is a factory function which returns a newly allocated instance of the component. For example:

    function createPosition() {
      return {
        x: 0,
        y: 0
      };
    }
  • reset is an optional function which alters a previously used component instance to a clean state so it can be reused on a new entity. For example:

    function resetPosition(position) {
      position.x = 0;
      position.y = 0;
    }
  • size is an optional number of instances to allocate initially.

addComponent(id, component)

Adds a new component to an entity, and returns it. If the component is newly added, the onAddComponent callbacks are fired. If the component already existed, it is reset.

  • id is the id of the entity to add the component to.
  • component is the name of the component to add.
var sprite = entities.addComponent(player, "sprite");
sprite.image = "something.png";

getComponent(id, component)

Returns the component value for an entity.

  • id is the id of the entity to get the component from.
  • component is the name of the component to get.
var sprite = entities.getComponent(player, "sprite");
sprite.image = "something.png";

setComponent(id, component, value)

Sets a primitive value for a component. To change a component that holds an object, use getComponent instead.

  • id is the id of the entity to set the component on.
  • component is the name of the component to set.
  • value is the primitive value to set.
entities.setComponent(player, "health", 100);

removeComponent(id, component)

Removes a component from an entity. The onRemoveComponent callbacks are fired for the removed component.

  • id is the id of the entity to remove the component from.
  • component is the name of the component to remove.
entities.removeComponent(player, "health");

onAddComponent(component, callback)

Registers a callback to be called when component is added to any entity. callback looks like:

function myAddCallback(id, component, value) { /* ... */ }

onRemoveComponent(component, callback)

Registers a callback to be called when component is removed from any entity. callback looks like:

function myRemoveCallback(id, component, removedValue) { /* ... */ }

registerSearch(search, components)

Registers a named search for entities that have all components listed in the components array.

  • search is the name of the search to register.
  • components is an array of component names that an entity must possess to be included in the results.
entities.registerSearch("collectables", ["size", "collisions"]);

find(search)

Returns a list of entity ids for all entities that match the search. See registerSearch.

  • search is the name of the search previously registered with registerSearch.
var collectables = entities.find("collectables"); // => [1, 2, 3, ...]

load(entities)

Load entities into an entity pool from an array of objects. load should only be used to fill an empty EntityPool.

  • entities is some JSON-compatible object returned by save. The format looks like:

    [
      {
        "id": 1,
        "componentName": "componentValue"
      },
      {
        "id": 2,
        "componentName": "componentValue"
      }
    ]

save()

Returns an object suitable for saving all entities in the EntityPool to a JSON file. See load().

Install

With npm do:

npm install --save entity-component-system

License

MIT

About

No description, website, or topics provided.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •