You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ECS.js is a easy to use [Entity Component System](https://en.wikipedia.org/wiki/Entity_component_system) for JavaScript. ECS.js will help you to easier develop your games by making composable pieces of code, mixing and remixing them with entities to your liking.
2
6
3
7
## Installation
4
8
```
5
9
npm i javascript-entity-component-system
6
10
```
7
11
8
-
## Why
9
-
I was interested in how these system work. I needed a simple library that isn't too big and doesn't have unnecessary features nobody really needs.
10
-
11
-
## What's a *Entity-Component-System* anyway?
12
-
There are alot of articles out there that explains the system. One of those that I used to understand is this [Entity System for Javascript](https://entity-system-js.readthedocs.io/en/latest/)
13
-
You will also see naming similarities in this library as I got inspired by it.
14
-
If you want a general explanation then head over to [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system)
15
-
16
-
## Features
17
-
- Gives the most basic features to get going
18
-
- it's small (*1.61kb minified*)
19
-
- no dependencies
20
-
- it has documentation
21
-
22
-
## Problems
23
-
- Because the philosophy of this library is to be lightweight and simple, I haven't found a solution yet to make rendering work in a intelligent manner (It would call the rendering processor multiple times per frame which is baaad), so for now use this only to update entities. However there are methods implemented to help you work inside your rendering function.
12
+
##Features
13
+
- ⚡ **Simple API** - ECS.js has a very simple and easy to use API with a mix of object-oriented and prodecural type of methods.
14
+
- 🥤 **No Dependencies** - ECS.js is built with TypeScript and compiled to JavaScript without the need of any external libraries. The source code is only ~250 lines long.
15
+
- 🤝 **TypeScript support** - ECS.js is built and is best used with TypeScript. Type defintions and hinting are provided naturally.
16
+
- 📄 **Documentation** - ECS.js has documentation about every method and examples on how to use them.
Remeber Components are just data. No logic at all. In this library I decided to go with Objects:
34
+
### Step 1: Components and Processors
35
+
#### Components
36
+
Let's start with **components**. Components are basically just containers with data. This is the basic structure:
44
37
```JavaScript
45
38
constPositionComponent= {
46
39
name:"Position",
@@ -52,20 +45,23 @@ const PositionComponent = {
52
45
```
53
46
54
47
The name property is **required**. It will define the name of the component and is important because it's an identifier for processors.
55
-
The state property however is not required. You can also define Components to just "mark" entities.
56
-
A component that doesn't have a state property could look like this:
48
+
The state property however is **not required**. That's useful if you want to mark entities:
57
49
```JavaScript
58
50
constGravityComponent= {
59
51
name:"Gravity"
60
52
}
61
53
```
62
54
63
-
#### "How do I define Processors?"
64
-
They are almost the same as Components. They are also Objects:
55
+
It works the same way as with state, except your processor won't have any data to use. Sometimes that's enough for a processor to do it's job. Don't worry if this doesn't make much sense yet, keep reading.
56
+
57
+
#### Processors
58
+
59
+
Now that we have a component defined, we can get on to **Processors**.
60
+
The structure of them is similar:
65
61
```JavaScript
66
62
constPullDownProcessor= {
67
63
name:"PullDown",
68
-
component:"Gravity",
64
+
target:"Gravity",
69
65
update(component, entities) {
70
66
entities.forEach(entity=> {
71
67
// Do something on those entities
@@ -74,9 +70,9 @@ const PullDownProcessor = {
74
70
}
75
71
```
76
72
77
-
All the properties you see are **required**. The first is the name of the processor and the second one is the component it should act upon. Then there is something that is different from the component Object. It's the update function.
73
+
All properties are **required**. The first one is the name of the processor and the second one is the component it should act upon. The third property is the update function, that's where the logic happens.
78
74
79
-
That function is being called every frame and basically inside of that you will write all your logic code. For example in this case this processor corresponds to the "Gravity" component. That means this processor has to pull (hence the name) entities down to earth.
75
+
That function will be called every frame. For example in this case this processor corresponds to the "Gravity" component. That means that this processor has to pull (hence the name) entities down to earth.
80
76
81
77
This could be done like so:
82
78
```JavaScript
@@ -88,15 +84,10 @@ update(component, entities) {
88
84
})
89
85
```
90
86
91
-
The update function will get 2 arguments passed down from the system. The first is the component this processor acts on, it can be useful in some cases but most of the time you don't need it. The second argument are the entities that all have a "Gravity" Component attached. You don't have to filter away the components you need. It will be done for you by the system, nice and simple.
92
-
93
-
With those you then can iterate through them (I used a .forEach as you can see) and then apply logic.
94
-
In some cases you will need to check for some other components, like here, you need a position component attached otherwise you can't apply gravity force to it.
87
+
The function will receive the component it's acting upon (Gravity) and all entities that have a Gravity component attached. You can see that we check the entities beforehand for a "Position" component. That's important here, because we want to apply the gravity to the position of the entity, which in this case they only have if there is a position component attached.
95
88
96
-
You can do that with **ECS.entityHasComponent()**. There is some explanation in the docs. Feel free to read it up :)
97
-
98
-
#### "How do I register my components and processors in the system?"
99
-
That's simple to do.
89
+
#### Register components and processors
90
+
Now the easy part. We have to register them in order to compose entities:
#### "Do we need to register those in the system too?"
121
-
Yup.
108
+
After that you register the player in the system:
122
109
```JavaScript
123
110
ECS.addEntity(Player)
124
111
```
125
112
126
-
The decision why you need to manually do it was because you then can create the entity first, make some changes in some properties where you don't feel like creating a whole new component is overkill and then insert it into the system.
127
-
This way gives more flexibility.
128
-
129
-
#### "Okay I got it but how does the system update my entites?"
130
-
Now you're almost done.
131
-
You now only need to call the update function of the system.
113
+
#### Step 3: Let the magic happen
114
+
You're soo close. Call the update function ```ECS.update()``` inside the gameloop.
132
115
```JavaScript
133
-
// You should do this every frame. Preferrably inside your gameloop.
116
+
// You should do this every frame. preferably inside your gameloop.
134
117
ECS.update()
135
118
```
136
119
137
-
And now everything is updating nicely :)
138
-
139
-
#### "How do I go from here?"
140
-
Well the only thing you have to worry about is to make more components and processors that act upon them.
141
-
142
-
Please note though that this system is designed for continous logic. Gravity for example is something that always acts on some entity. Having a player get damage for couple of seconds is not continous. I am experimenting with some solutions for this and there are for sure some hacks you can do to make it work but I would suggest you only use this for continous effects and make something yourself for one-time-effects.
143
-
144
-
One solution would be to add Components that does damage the some entity and then dettach it from the entity again after couple of seconds but it wouldn't be all that easy. You would have to define couple of variables that keep track of the time that has elapsed etc.
145
-
146
-
However I do have some helper methods implemented in the library that can ease the pain to code one-time-effects and would like to know how you guys cope this.
120
+
### What's next?
121
+
Well the only thing you have to worry about now is to make more components and processors that act upon them.
147
122
148
-
Other than that have fun deving! :)
123
+
In a ECS, components and processors are your bread and butter. You write those to have effects on your entities. The real strength comes through when you realize that you can mix and match components to your liking. This enables CRAZY flexibility. That's why it's such a often used pattern in game development. Enjoy :)
0 commit comments