Skip to content
This repository has been archived by the owner on Jun 1, 2022. It is now read-only.

Commit

Permalink
Merge branch 'master' of github.com:MozillaReality/ecsy
Browse files Browse the repository at this point in the history
  • Loading branch information
robertlong committed Sep 10, 2020
2 parents d7f9f11 + 498fb64 commit ca18575
Show file tree
Hide file tree
Showing 41 changed files with 801 additions and 287 deletions.
33 changes: 33 additions & 0 deletions AWESOME_ECSY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,48 @@ Feel free to submit PRs with more links!

## Components & Systems
- ECSY Two, uses HTML canvas instead of WebGL: https://github.com/joshmarinacci/ecsy-two/
- ECSY Threejs: https://github.com/MozillaReality/ecsy-three
- ECSY Physics system https://github.com/HydraFire/ecsy-physics-system
- ECSY Networking: https://github.com/xr3ngine/ecsy-networking
- ECSY Babylon: https://github.com/megavr/ecsy-babylon
- ECSY Ember Babylon: https://github.com/kaliber5/ember-ecsy-babylon
- ECSY Babylon: https://github.com/kaliber5/ecsy-babylon
- ECSY Babylon examples: https://github.com/megavr/ecsy-babylon-examples
- ECSY Actors (Input action handling, state management, axis blending and event output for character controllers and stateful, interactive objects): https://github.com/xr3ngine/ecsy-actors

## Engines built on top of ECSY
- XREngine: https://github.com/xr3ngine/xr3ngine
- HekoJS https://github.com/hekojs/core
- A Behavioral ECS game engine https://github.com/xr3ngine/armada

## Demos, games and applications
- Hello WebXR: https://mixedreality.mozilla.org/hello-webxr
- Jumpy Balls: https://mixedreality.mozilla.org/jumpy-balls
- Steam Dungeon: http://steamdungeon.com/
- ETLU - Extract Transform Load Universe: https://github.com/aaronanderson/etlu
- Thermal runway. code: https://github.com/macaco-maluco/thermal-runway game: https://thermalrunway.macacomaluco.space/
- NES emulator with ECSY and Rust: https://github.com/takahirox/nes-rust-ecsy
- Jingle Mash https://github.com/joshmarinacci/jinglesmash-ecs
- WebXR Simgame https://github.com/joshmarinacci/webxr-simgame
- Vitruvius 2 player game https://github.com/terrygonguet/vitruvius
- Space shooter multiplayer: https://github.com/nickyvanurk/3d-multiplayer-browser-shooter
- Beat pads music game https://github.com/fernandojsg/beatpads
- Soft body simulation https://github.com/philsawicki/soft-body-simulation
- VoxelJS Next https://github.com/joshmarinacci/voxeljs-next
- Grapher https://github.com/SolarLiner/grapher
- Conquer covid https://github.com/loqwai/conquer-covid
- ECSY babylon study https://github.com/pocka/ecsy-babylonjs-study

## Tools
- ECSY Devtools: https://github.com/MozillaReality/ecsy-devtools

## Boilerplates
- ECSY webpack: https://github.com/MozillaReality/ecsy-webpack-boilerplate
- ECSY-three webpack: https://github.com/MozillaReality/ecsy-three-webpack
- ECSY typescript: https://github.com/robertlong/ecsy-typescript-boilerplate
- ECSY Pixi: https://github.com/manueldeval/ecsypixi
- ECSY React https://github.com/jmswrnr/react-ecs

## Articles
- ECSY Devtools introduction: https://blog.mozvr.com/ecsy-developer-tools/
- Introducing ECSY: https://blog.mozvr.com/introducing-ecsy/
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ For detailed information on the architecture and API please visit the [documenta
- Modern Javascript: ES6, classes, modules,...
- Pool for components and entities

## Goals
Our goal is for ECSY to be a lightweight, simple, and performant ECS library that can be easily extended and encoruages open source collaboration.

ECSY will not ship with features that bind it to a rendering engine or framework. Instead, we encourage the community to build framework specific projects like [ecsy-three](https://github.com/MozillaReality/ecsy-three), [ecsy-babylon](https://github.com/kaliber5/ecsy-babylon), and [ecsy-two](https://github.com/joshmarinacci/ecsy-two).

ECSY does not adhere strictly to "pure ECS design". We focus on APIs that push users towards good ECS design like putting their logic in systems and data in components. However, we will sometimes break the rules for API ergonomics, performance in a JS context, or integration with non-ECS frameworks.

ECSY is designed for a community driven ecosystem. We encourage users to come up with modular components and systems that can be composed into larger games, apps, and engines.

# Examples
- Ball example:
- three.js: https://ecsy.io/examples/ball-example/three
Expand Down
50 changes: 35 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ecsy",
"version": "0.3.2",
"version": "0.4.1",
"description": "Entity Component System in JS",
"main": "lib/index.js",
"module": "src/index.js",
Expand Down Expand Up @@ -56,6 +56,7 @@
"@babel/core": "^7.10.2",
"@babel/plugin-transform-modules-commonjs": "^7.10.1",
"@rollup/plugin-node-resolve": "^8.0.1",
"@rollup/plugin-replace": "^2.3.3",
"ava": "^3.9.0",
"babel-eslint": "^10.0.3",
"benchmarker-js": "0.0.3",
Expand All @@ -69,7 +70,7 @@
"http-server": "^0.11.1",
"nodemon": "^1.19.4",
"np": "^6.2.4",
"prettier": "^1.19.1",
"prettier": "^2.0.5",
"rimraf": "^3.0.2",
"rollup": "^1.29.0",
"rollup-plugin-json": "^4.0.0",
Expand Down
18 changes: 16 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import json from "rollup-plugin-json";
import resolve from "@rollup/plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import replace from "@rollup/plugin-replace";

export default [
{
input: "src/index.js",
plugins: [json({ exclude: ["node_modules/**"] })],
plugins: [
replace({
"process.env.NODE_ENV": JSON.stringify("development"),
delimiters: ["", ""]
}),
json({ exclude: ["node_modules/**"] })
],
output: [
{
format: "umd",
Expand Down Expand Up @@ -35,7 +42,14 @@ export default [
},
{
input: "src/index.js",
plugins: [json({ exclude: ["node_modules/**"] }), terser()],
plugins: [
replace({
"process.env.NODE_ENV": JSON.stringify("production"),
delimiters: ["", ""]
}),
json({ exclude: ["node_modules/**"] }),
terser()
],
output: [
{
format: "umd",
Expand Down
87 changes: 85 additions & 2 deletions site/docs/manual/Architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ By default your application should have at least one `world`. A world is basical
world = new World();
```

The `World` constructor accepts an option object with the following parameters:
- ***entityClass***: Provide the base class for entities that implements or extends `Entity`.
- ***entityPoolSize***: Define the initial entity pool size for entities. It can help to avoid GC during execution if the application expands the pool dynamically at execution time.

```javascript
// We know we will initially have around 10k enemies in our game so let's allocate 10k enemies initially and expand the pool as needed.
world = new World({ entityPoolSize: 10000 });
```

## Components
A `Component` ([API Reference](/api/classes/component)) is an object that can store data but should have not behaviour (As that should be handled by systems). There is not a mandatory way to define a component.

Expand Down Expand Up @@ -393,7 +402,7 @@ Components can be accessed from an entity in two ways:
- `getComponent(Component)`: Get the component for read only operations.
- `getMutableComponent(Component)`: Get the component to modify its values.

If `DEBUG` mode is enabled it will throw an error if you try to modify a component accessed by `getComponent`, but that error will not be thrown on release mode because of performance reasons.
If `development` mode is enabled it will throw an error if you try to modify a component accessed by `getComponent`, but that error will not be thrown on release mode because of performance reasons.

These two access modes help to implement `reactive queries`([more info](/manual/Architecture?id=reactive-queries)), which are basically lists of entities populated with components that have mutated somehow, without much overhead on the execution as we avoid using custom setters or proxies.
This means every time you request a mutable component, it will get marked as modified and systems listening for that will get notified accordingly.
Expand Down Expand Up @@ -508,11 +517,41 @@ class SystemName extends System {

If there is a `reactive query` (A query that *listens* for entities added or removed to it or which components has changed, [more info](/manual/Architecture?id=reactive-queries)) on the list of queries defined by a system, this system is called `reactive system` as it will react to changes on the entities and its components.

If you plan to mutate the results of a query while you are iterating it (eg: adding or removing components that will not match the query structure anymore, or removing the entity itself) you should traverse the results in reverse order:
```javascript
let results = this.queries.queryA.results;
for (var i = 0; i < results.length; i++) {
let entity = results[i];
if (i === 1) {
// This will cause the results list to be mutated, results.length will be decremented and you won't reach the end elements.
entity.remove();
}
}

// The correct way to do it
let results = this.queries.queryA.results;
for (var i = results.length - 1; i >= 0; i++) {
let entity = results[i];
if (i === 1) {
// This will modify the length of the results but as we are moving backward it won't affect us
entity.remove();
}
}
```

### Registering a system

Systems should be registered in a world in order to initialize them and add them to the default scheduler that will execute them on each frame.
```javascript
world.registerSystem(SystemName);
world.registerSystem(SystemClass);
```

### Unregistering a system

Systems can be unregistered, and they will get removed from the execution queue and the world. So if you want to use them again you need to register them again.
If you just want to temporaly disable its execution, you must use `System.stop()/play()` instead.
```javascript
world.unregisterSystem(SystemClass);
```

### Execution order
Expand Down Expand Up @@ -785,3 +824,47 @@ But if `SystemB` does the same, just `SystemC` will be able to react to it, as t
Because of that is important that you define an appropriate execution order based on the needs for your reactive systems.

There is one special use case when removing components and entities. When using `System State Components` they should be removed explicitly and they will not get removed if `entity.remove` is being called. [More info](/manual/Architecture?id=system-state-components)

## Extending core functionality

It is possible to provide a custom `Entity` class to modify the default behaviour.
To do so you need to import `_Entity` from `ecsy` and extend it in your class definition:
```javascript
import { _Entity, World } from "entity";

class MyEntity extends _Entity {
customMethod() {}
}

// Use the new entity class
let world = new World({ entityClass: MyEntity });
let entity = world.createEntity();

// Call our custom method on our entity class
entity.customMethod();
```
You can see an example of this extensibility in `ecsy-three`. In `ecsy-three` we extend both the entity class: https://github.com/MozillaReality/ecsy-three/blob/dev/src/core/entity.js and also the world class: https://github.com/MozillaReality/ecsy-three/blob/dev/src/core/world.js

## Developing

### Debug mode
ECSY will output some debug messages when in development mode. Development mode is active depending on the environment you are running ECSY in.

In CommonJS environments it is controlled by the value of the `NODE_ENV` environment variable. This means Webpack and similar tools can change the value for development and production builds. This ensures you get helpful messages during development and a smaller bundle size in production.

When using the UMD or ES Module builds then the unminified builds will have development mode on and the minified builds will have it turned off.

### Benchmarks

ECSY includes benchmarks (https://github.com/MozillaReality/ecsy/tree/dev/benchmarks) to test the performance and detect regressions.
To run the benchmarks locally you need to execute `npm run benchmarks`:
It will dump a JSON with the results of all the benchmarks and it will write a `benchmark_result.json` file.

You can use that file to compare against other executions by using `benchmarker` (`https://github.com/fernandojsg/benchmarker`):
```
# Install benchmarker globally
> npm install -g benchmarker-js
> benchmarker compare results1.json results2.json
```
It will dump a table with a summary comparing all the executions. This can be useful when doing big refactors to compare across different branches to make sure that there is not regression in performance.
7 changes: 4 additions & 3 deletions site/docs/manual/Getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ for (let i = 0; i < 10; i++) {
.addComponent(Position, { x: Math.random() * 10, y: Math.random() * 10, z: 0});
}
```
With that, we have just created 11 entities. 10 with the `Acceleration` and `Position` components, and one with just the `Position` component.
Notice that the Position component is added using custom parameters. If we didn't use the parameters then the
component would use the default values declared in the Position class.

With that, we have just created 11 entities. 10 with the `Acceleration` and `Position` components, and one with just the `Position` component.
Notice that the `Position` component is added using custom parameters. If we didn't use the parameters then the
component would use the default values declared in the `Position` class.

## Creating a system
Now we are going to define a [system](/manual/Architecture?id=systems) to process the components we just created.
Expand Down
16 changes: 8 additions & 8 deletions site/examples/ball-example/three/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@

var world = new World();

world
.registerSystem(RotatingSystem)
.registerSystem(PulsatingColorSystem)
.registerSystem(PulsatingScaleSystem)
.registerSystem(TimeoutSystem)
.registerSystem(ColliderSystem)
.registerSystem(MovingSystem);

world
.registerComponent(Object3D)
.registerComponent(Collidable)
Expand All @@ -44,6 +36,14 @@
.registerComponent(Colliding)
.registerComponent(Rotating);

world
.registerSystem(RotatingSystem)
.registerSystem(PulsatingColorSystem)
.registerSystem(PulsatingScaleSystem)
.registerSystem(TimeoutSystem)
.registerSystem(ColliderSystem)
.registerSystem(MovingSystem);

var camera, scene, renderer, parent;
var clock = new THREE.Clock();

Expand Down
Loading

0 comments on commit ca18575

Please sign in to comment.