All Projects → fenomas → ent-comp

fenomas / ent-comp

Licence: other
A light, fast Entity Component System in JS

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to ent-comp

Octopuskit
2D ECS game engine in 100% Swift + SwiftUI for iOS, macOS, tvOS
Stars: ✭ 246 (+884%)
Mutual labels:  ecs, entity-component-system
Gdk For Unity Fps Starter Project
SpatialOS GDK for Unity FPS Starter Project
Stars: ✭ 119 (+376%)
Mutual labels:  ecs, entity-component-system
Entitas Sync Framework
Networking framework for Entitas ECS. Targeted at turnbased games or other slow-paced genres.
Stars: ✭ 98 (+292%)
Mutual labels:  ecs, entity-component-system
SpaceWar-ECS
A space war game made with ECS and JobSystem in Unity.
Stars: ✭ 26 (+4%)
Mutual labels:  ecs, entity-component-system
Uecs
Ubpa Entity-Component-System (U ECS) in Unity3D-style
Stars: ✭ 174 (+596%)
Mutual labels:  ecs, entity-component-system
Rust Game Development Frameworks
List of curated frameworks by the **Game Development in Rust** community.
Stars: ✭ 81 (+224%)
Mutual labels:  ecs, entity-component-system
Edyn
Edyn is a real-time physics engine organized as an ECS.
Stars: ✭ 113 (+352%)
Mutual labels:  ecs, entity-component-system
Ecs.hpp
C++17 Entity Component System
Stars: ✭ 25 (+0%)
Mutual labels:  ecs, entity-component-system
Ape Ecs
Entity-Component-System library for JavaScript.
Stars: ✭ 137 (+448%)
Mutual labels:  ecs, entity-component-system
Flecs
A fast entity component system (ECS) for C & C++
Stars: ✭ 2,201 (+8704%)
Mutual labels:  ecs, entity-component-system
Learning Unity Ecs 2
A bunch of small Unity projects where I explore and learn Unity's new ECS and Job System. Updated for the new API.
Stars: ✭ 65 (+160%)
Mutual labels:  ecs, entity-component-system
Egocs
EgoCS: An Entity (GameObject) Component System framework for Unity3D
Stars: ✭ 211 (+744%)
Mutual labels:  ecs, entity-component-system
Endless Runner Entitas Ecs
Runner template for Unity
Stars: ✭ 41 (+64%)
Mutual labels:  ecs, entity-component-system
ECS
Entity-Component-System
Stars: ✭ 122 (+388%)
Mutual labels:  ecs, entity-component-system
Ecs
A simple and easy to use entity-component-system C++ library
Stars: ✭ 20 (-20%)
Mutual labels:  ecs, entity-component-system
Entitas Lite
Entitas-Lite is a No-CodeGenerator branch of Entitas, and also a fast & easy ECS framework for C#/Unity.
Stars: ✭ 106 (+324%)
Mutual labels:  ecs, entity-component-system
Ecs
LeoECS is a fast Entity Component System (ECS) Framework powered by C# with optional integration to Unity
Stars: ✭ 578 (+2212%)
Mutual labels:  ecs, entity-component-system
Svelto.ecs
Svelto ECS C# Lightweight Data Oriented Entity Component System Framework
Stars: ✭ 605 (+2320%)
Mutual labels:  ecs, entity-component-system
Pyro
A linear Entity Component System
Stars: ✭ 125 (+400%)
Mutual labels:  ecs, entity-component-system
Awesome Entity Component System
😎 A curated list of Entity-Component-System (ECS) libraries and resources
Stars: ✭ 180 (+620%)
Mutual labels:  ecs, entity-component-system

ent-comp

A light, fast entity-component system in JS with no dependencies.

Overview

An Entity Component System (ECS) is a programming construct that solves a very common problem in gamedev. It lets you easily model dynamic systems where the entities are difficult to describe with OO-style inheritance.

This library is the distilled result of my playing with a bunch of ECS libraries, removing what wasn't useful, and rejiggering what remained to perform well in the most important cases. Specifically it's tuned to be fast at accessing the state of a given entity/component, and looping over all states for a given component.

To get started, check the usage examples below, or the API reference.

Installation:

To use as a dependency:

npm install ent-comp

To hack on it:

git clone https://github.com/fenomas/ent-comp.git
cd ent-comp
npm install
npm test         # run tests
npm run bench    # run benchmarks
npm run doc      # rebuild API docs

API reference:

See api.md.

Basic usage:

Create the ECS, entities, and components thusly:

var EntComp = require('ent-comp')
var ecs = new EntComp()

// Entities are simply integer IDs:
var playerID = ecs.createEntity() // 1
var monsterID = ecs.createEntity() // 2

// components are defined with a definition object:
ecs.createComponent({
	name: 'isPlayer'
})

// component definitions can be accessed by name
ecs.components['isPlayer']  // returns the definition object

Once you have some entities and components, you can add them, remove them, and check their existence:

ecs.addComponent(playerID, 'isPlayer')
ecs.hasComponent(playerID, 'isPlayer') // true

ecs.removeComponent(playerID, 'isPlayer')
ecs.hasComponent(playerID, 'isPlayer') // false

// when creating an entity you can pass in an array of components to add
var id = ecs.createEntity([ 'isPlayer', 'other-component' ]) 

The trivial example above implements a stateless component, which can be used like a boolean flag for entities. But most real components will also need to manage some data for each entity. This is done by giving the component a state object, and using the #getState method.

// createComponent returns the component name, for convenience
var locationComp = ecs.createComponent({
	name: 'location',
	state: { x:0, y:0, z:0 },
})

// give the player entity a location component
ecs.addComponent(playerID, locationComp)

// grab its state to update its data
var loc = ecs.getState(playerID, locationComp)
loc.y = 37

// you can also pass in initial state values when adding a component:
ecs.addComponent(monsterID, locationComp, { y: 42 })
ecs.getState(monsterID, locationComp) // { x:0, y:42, z:0 }

When a component is added to an entity, its state object is automatically populated with an __id property denoting the entity's ID.

loc.__id // same as playerID

Components can also have onAdd and onRemove properties, which get called as any entity gains or loses the component.

ecs.createComponent({
	name: 'orientation',
	state: { angle:0 },
	onAdd: (id, state) => {
		// initialize to a random direction
		state.angle = 360 * Math.random()
	},
	onRemove: (id, state) => {
		console.log('orientation removed from entity', id)
	}
})

Finally, components can define system and/or renderSystem functions. When your game ticks or renders, call the appropriate library methods, and each component system function will get passed a list of state objects for all the entities that have that component.

Components can also define an order property (default 99), to specify the order in which systems fire (lowest to highest).

ecs.createComponent({
	name: 'hitPoints',
	state: { hp: 100 },
	order: 10,
	system: function(dt, states) {
		// states is an array of entity state objects
		states.forEach(state => {
			if (state.hp <= 0) console.log('Dead entity!', state.__id)
		})
	},
	renderSystem: function(dt, states) {
		states.forEach(state => {
			var id = state.__id
			var hp = state.hp
			drawTheEntityHitpoints(id, hp) 
		})
	},
})

// calling tick/render triggers the systems
ecs.tick( tick_time )
ecs.render( render_time )

See the API reference for details on each method.

Multi-components

This library now supports multi components, where a component can be added to the same entity multiple times. Each addition creates a separate state object.

API may change someday, but for now all ECS methods that normally return a state object instead return an array of state objects. Calling removeComponent will remove all multi-component instances for that entity, and there's a new removeMultiComponent(id, name, index) API to remove them individually (by their index in the array).

In practice it looks like this:

ecs.createComponent({
	name: 'buff',
	multi: true, // this marks the component as multi
	state: { buffName: '', duration: 100 },
	system: function(dt, stateLists) {
		// stateLists is the array of all ent/comp pairs
		stateLists.forEach(statesArr => {
			// statesArr is an array of multi components for this entity
			statesArr.forEach((state, i) => {
				// update the state of this particular entity's buff
				state.duration -= dt
				if (state.duration < 0) {
					ecs.removeMultiComponent(state.__id, 'buff', i)
				}
			})
		})
	},
})

Further usage:

If you need to query certain components many times each frame, you can create bound accessor functions to get the existence or state of a given component. These accessors are moderately faster than getState and hasComponent.

var hasLocation = ecs.getComponentAccessor('location')
hasLocation(entityID) // true or false

var getLocation = ecs.getStateAccessor('location')
getLocation(entityID) // returns a state object

There's also an API for getting an array of all state objects for a given component.

var states = ecs.getStatesList('hitPoints')
// returns the same array that gets passed to `system` functions

Caveat about complex state objects:

When you add a component to an entity, a new state object is created for that ent/comp pair. This new state object is a shallow copy of the component's default state, not a duplicate or deep clone. This means any non-primitive state properties will be copied by reference.

What this means to you is, state objects containing nested objects or arrays probably won't do what you intended. For example:

ecs.createComponent({
	name: 'foo',
	state: {
		vector3: [0,0,0]
	}
})

If you define a component that way, all its state objects will contain references to the same array. You probably want each to have its own, which you can do by initializing them in the onAdd handler:

ecs.createComponent({
	name: 'foo',
	state: {
		vector3: null
	},
	onAdd: function(id, state) {
		if (!state.vector3) state.vector3 = [0,0,0]
	}
})

Testing for the value before overwriting means that you can pass in an initial value when adding the component, and it will still do what you expect:

ecs.addComponent(id, 'foo', { vector3: [1,1,1] })

Things this library doesn't do:

  1. Assemblages. I can't for the life of me see how they add any value. If I'm missing something please file an issue.

  2. Provide any way of querying which entities have components A and B, but not C, and so on. If you need this, I think maintaining your own lists will be faster (and probably easier to use) than anything the library could do automatically.

Change list

  • 0.10.0
    • Changes internals such that removals and deletions are handled immediately. Removes the need for immediately arguments on such methods.
  • 0.9.0
    • Adds order property to component definitions
  • 0.7.0
    • Internals rebuilt and bugs fixed, should be no API changes
  • 0.6.0
    • removeComponent changed to be deferred by default
    • removeComponentLater removed
    • Adds multi-tagged components, and removeMultiComponent
    • Doubles performance of hasComponent and getState (for some reason..)

Author: https://github.com/fenomas

License: MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].