├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── docs
├── assets
│ ├── css
│ │ ├── main.css
│ │ └── main.css.map
│ ├── images
│ │ ├── icons.png
│ │ ├── icons@2x.png
│ │ ├── widgets.png
│ │ └── widgets@2x.png
│ └── js
│ │ ├── main.js
│ │ └── search.js
├── classes
│ ├── _engine_.engine.html
│ ├── _entity_.entity.html
│ ├── _family_.abstractfamily.html
│ ├── _family_.cachedfamily.html
│ ├── _family_.familybuilder.html
│ ├── _family_.noncachedfamily.html
│ └── _system_.system.html
├── globals.html
├── index.html
├── interfaces
│ ├── _component_.component.html
│ ├── _component_.componentclass.html
│ ├── _engine_.engineentitylistener.html
│ └── _family_.family.html
└── modules
│ ├── _component_.html
│ ├── _engine_.html
│ ├── _entity_.html
│ ├── _family_.html
│ ├── _index_.html
│ └── _system_.html
├── index.d.ts
├── index.js
├── lib
├── Component.d.ts
├── Component.js
├── Component.js.map
├── Engine.d.ts
├── Engine.js
├── Engine.js.map
├── Entity.d.ts
├── Entity.js
├── Entity.js.map
├── Family.d.ts
├── Family.js
├── Family.js.map
├── System.d.ts
├── System.js
├── System.js.map
├── index.d.ts
├── index.js
└── index.js.map
├── package-lock.json
├── package.json
├── src
├── Component.ts
├── Engine.ts
├── Entity.spec.ts
├── Entity.ts
├── Family.spec.ts
├── Family.ts
├── System.spec.ts
├── System.ts
├── index.spec.ts
└── index.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | package-lock.json
3 | .gitignore
4 | node_modules
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nova Engine - Entity-Component-System
2 |
3 | An entity component system made with typescript for usage in the Nova Engine.
4 |
5 | ## Installing
6 |
7 | ```sh
8 | npm i --save @nova-engine/ecs
9 | ```
10 |
11 | ## Basic Usage
12 |
13 | To use the entity component system, you first must create your Engine to store your systems and entities.
14 |
15 | You can create as many as you wish, but usually it's only one per application.
16 |
17 | ```ts
18 | import { Engine } from "@nova-engine/ecs";
19 | const engine = new Engine();
20 | ```
21 |
22 | Now you just define your components:
23 |
24 | ```ts
25 | import { Component } from "@nova-engine/ecs";
26 |
27 | // Components can have custom constructors, but they must be able to be initialized
28 | // with no arguments, because entities creates the instances for you.
29 | // Try not to save complex data types in yout components
30 | class PositionComponent implements Component {
31 | x = 0;
32 | y = 0;
33 | }
34 |
35 | class VelocityComponent implements Component {
36 | x = 0;
37 | y = 0;
38 | }
39 |
40 | // If you are making a component library, and want to avoid collitions
41 | // You can add a tag to your component implementations
42 |
43 | class MyLibraryComponent implements Component {
44 | // This will ensure your component won't collide with other "MyLibraryComponent"
45 | static readonly tag = "my-library/MyLibraryComponent";
46 | }
47 | ```
48 |
49 | You can also define your systems:
50 |
51 | ```ts
52 | import { Component, Family, System, FamilyBuilder } from "@nova-engine/ecs";
53 | class GravitySystem extends System {
54 | static readonly DEFAULT_ACCELERATION = 0.98;
55 | family?: Family;
56 | acceleration: number;
57 |
58 | // Constructors are free for your own implementation
59 | constructor(acceleration = GravitySystem.DEFAULT_ACCELERATION) {
60 | super();
61 | this.acceleration = acceleration;
62 | // higher priorities means the system runs before others with lower priority
63 | this.priority = 300;
64 | }
65 | // This is called when a system is added to an engine, you may want to
66 | // startup your families here.
67 | onAttach(engine: Engine) {
68 | // Needed to work properly
69 | super.onAttach(engine);
70 | // Families are an easy way to have groups of entities with some criteria.
71 | this.family = new FamilyBuilder(engine).include(VelocityComponent).build();
72 | }
73 |
74 | // This, in reality is the only method your system must implement
75 | // but using onAttach to prepare your families is useful.
76 | update(engine: Engine, delta: number) {
77 | for (let entity of this.family.entities) {
78 | // Easy to get a component by class
79 | // Be warned, if the entity lacks this component, an error *will* be thrown.
80 | // But families ensures than we will always have the required components.
81 | const velocity = entity.getComponent(VelocityComponent);
82 | velocity.y += this.acceleration;
83 | // if the family doesn't require that component
84 | // you can always check for it
85 | if (entity.hasComponent(PositionComponent)) {
86 | const position = entity.getComponent(PositionComponent);
87 | } else {
88 | // You can create components on an entity easily.
89 | const position = entity.putComponent(PositionComponent);
90 | }
91 | }
92 | }
93 | }
94 | ```
95 |
96 | ## Limitations
97 |
98 | You can only have one instance of a component per entity.
99 | entity IDs are not generated by default, if you need them to have IDs, set them up yourself:
100 |
101 | ```ts
102 | entity.id = myGeneratedId();
103 | ```
104 |
105 | ## LICENSE
106 |
107 | The license is Apache-2.0, so use it as you please without worries.
108 |
--------------------------------------------------------------------------------
/docs/assets/images/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nova-engine/ecs/092352e32e88b3525369578c2d8a60d551b0071c/docs/assets/images/icons.png
--------------------------------------------------------------------------------
/docs/assets/images/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nova-engine/ecs/092352e32e88b3525369578c2d8a60d551b0071c/docs/assets/images/icons@2x.png
--------------------------------------------------------------------------------
/docs/assets/images/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nova-engine/ecs/092352e32e88b3525369578c2d8a60d551b0071c/docs/assets/images/widgets.png
--------------------------------------------------------------------------------
/docs/assets/images/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nova-engine/ecs/092352e32e88b3525369578c2d8a60d551b0071c/docs/assets/images/widgets@2x.png
--------------------------------------------------------------------------------
/docs/globals.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
@nova-engine/ecs
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Index
68 |
69 |
70 |
71 | External modules
72 |
80 |
81 |
82 |
83 |
84 |
85 |
116 |
117 |
118 |
119 |
120 |
Legend
121 |
122 |
123 | Module
124 | Object literal
125 | Variable
126 | Function
127 | Function with type parameter
128 | Index signature
129 | Type alias
130 |
131 |
132 | Enumeration
133 | Enumeration member
134 | Property
135 | Method
136 |
137 |
138 | Interface
139 | Interface with type parameter
140 | Constructor
141 | Property
142 | Method
143 | Index signature
144 |
145 |
146 | Class
147 | Class with type parameter
148 | Constructor
149 | Property
150 | Method
151 | Accessor
152 | Index signature
153 |
154 |
155 | Inherited constructor
156 | Inherited property
157 | Inherited method
158 | Inherited accessor
159 |
160 |
161 | Protected property
162 | Protected method
163 | Protected accessor
164 |
165 |
166 | Private property
167 | Private method
168 | Private accessor
169 |
170 |
171 | Static property
172 | Static method
173 |
174 |
175 |
176 |
177 |
178 |
Generated using TypeDoc
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
@nova-engine/ecs
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
Nova Engine - Entity-Component-System
68 |
An entity component system made with typescript for usage in the Nova Engine.
69 |
Installing
70 |
npm i --save @nova-engine/ecs
71 |
72 |
Basic Usage
73 |
To use the entity component system, you first must create your Engine to store your systems and entities.
74 |
You can create as many as you wish, but usually it's only one per application.
75 |
import { Engine } from "@nova-engine/ecs" ;
76 | const engine = new Engine();
77 |
78 |
Now you just define your components:
79 |
import { Component } from "@nova-engine/ecs" ;
80 |
81 |
82 |
83 |
84 | class PositionComponent implements Component {
85 | x = 0 ;
86 | y = 0 ;
87 | }
88 |
89 | class VelocityComponent implements Component {
90 | x = 0 ;
91 | y = 0 ;
92 | }
93 |
94 |
95 |
96 |
97 | class MyLibraryComponent implements Component {
98 |
99 | static readonly tag = "my-library/MyLibraryComponent" ;
100 | }
101 |
102 |
You can also define your systems:
103 |
import { Component, Family, System, FamilyBuilder } from "@nova-engine/ecs" ;
104 | class GravitySystem extends System {
105 | static readonly DEFAULT_ACCELERATION = 0.98 ;
106 | family?: Family;
107 | acceleration: number ;
108 |
109 |
110 | constructor (acceleration = GravitySystem.DEFAULT_ACCELERATION ) {
111 | super ();
112 | this .acceleration = acceleration;
113 |
114 | this .priority = 300 ;
115 | }
116 |
117 |
118 | onAttach(engine: Engine) {
119 |
120 | super .onAttach(engine);
121 |
122 | this .family = new FamilyBuilder(engine).include(VelocityComponent).build();
123 | }
124 |
125 |
126 |
127 | update(engine: Engine, delta: number ) {
128 | for (let entity of this .family.entities) {
129 |
130 |
131 |
132 | const velocity = entity.getComponent(VelocityComponent);
133 | velocity.y += this .acceleration;
134 |
135 |
136 | if (entity.hasComponent(PositionComponent)) {
137 | const position = entity.getComponent(PositionComponent);
138 | } else {
139 |
140 | const position = entity.putComponent(PositionComponent);
141 | }
142 | }
143 | }
144 | }
145 |
146 |
Limitations
147 |
You can only have one instance of a component per entity.
148 | entity IDs are not generated by default, if you need them to have IDs, set them up yourself:
149 |
entity.id = myGeneratedId();
150 |
151 |
LICENSE
152 |
The license is Apache-2.0, so use it as you please without worries.
153 |
154 |
155 |
186 |
187 |
188 |
189 |
190 |
Legend
191 |
192 |
193 | Module
194 | Object literal
195 | Variable
196 | Function
197 | Function with type parameter
198 | Index signature
199 | Type alias
200 |
201 |
202 | Enumeration
203 | Enumeration member
204 | Property
205 | Method
206 |
207 |
208 | Interface
209 | Interface with type parameter
210 | Constructor
211 | Property
212 | Method
213 | Index signature
214 |
215 |
216 | Class
217 | Class with type parameter
218 | Constructor
219 | Property
220 | Method
221 | Accessor
222 | Index signature
223 |
224 |
225 | Inherited constructor
226 | Inherited property
227 | Inherited method
228 | Inherited accessor
229 |
230 |
231 | Protected property
232 | Protected method
233 | Protected accessor
234 |
235 |
236 | Private property
237 | Private method
238 | Private accessor
239 |
240 |
241 | Static property
242 | Static method
243 |
244 |
245 |
246 |
247 |
248 |
Generated using TypeDoc
249 |
250 |
251 |
252 |
253 |
254 |
--------------------------------------------------------------------------------
/docs/interfaces/_component_.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Component | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
65 |
Interface Component
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Hierarchy
74 |
75 |
76 | Component
77 |
78 |
79 |
80 |
81 |
122 |
123 |
124 |
125 |
126 |
Legend
127 |
128 |
129 | Module
130 | Object literal
131 | Variable
132 | Function
133 | Function with type parameter
134 | Index signature
135 | Type alias
136 |
137 |
138 | Enumeration
139 | Enumeration member
140 | Property
141 | Method
142 |
143 |
144 | Interface
145 | Interface with type parameter
146 | Constructor
147 | Property
148 | Method
149 | Index signature
150 |
151 |
152 | Class
153 | Class with type parameter
154 | Constructor
155 | Property
156 | Method
157 | Accessor
158 | Index signature
159 |
160 |
161 | Inherited constructor
162 | Inherited property
163 | Inherited method
164 | Inherited accessor
165 |
166 |
167 | Protected property
168 | Protected method
169 | Protected accessor
170 |
171 |
172 | Private property
173 | Private method
174 | Private accessor
175 |
176 |
177 | Static property
178 | Static method
179 |
180 |
181 |
182 |
183 |
184 |
Generated using TypeDoc
185 |
186 |
187 |
188 |
189 |
190 |
--------------------------------------------------------------------------------
/docs/interfaces/_component_.componentclass.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ComponentClass | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
65 |
Interface ComponentClass<T>
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Type parameters
74 |
79 |
80 |
81 | Hierarchy
82 |
83 |
84 | ComponentClass
85 |
86 |
87 |
88 |
89 | Index
90 |
91 |
92 |
93 | Constructors
94 |
97 |
98 |
99 | Properties
100 |
104 |
105 |
106 |
107 |
108 |
109 | Constructors
110 |
111 |
112 | constructor
113 |
114 | new ComponentClass( ) : T
115 |
116 |
117 |
118 |
119 |
120 | Defined in Component.ts:5
121 |
122 |
123 | Returns T
124 |
125 |
126 |
127 |
128 |
129 | Properties
130 |
131 |
132 | name
133 | name: string
134 |
135 |
136 | Defined in Component.ts:4
137 |
138 |
139 |
140 |
141 |
142 | Optional tag
143 | tag: undefined | string
144 |
145 |
146 | Defined in Component.ts:5
147 |
148 |
149 |
150 |
151 |
152 |
204 |
205 |
206 |
207 |
208 |
Legend
209 |
210 |
211 | Module
212 | Object literal
213 | Variable
214 | Function
215 | Function with type parameter
216 | Index signature
217 | Type alias
218 |
219 |
220 | Enumeration
221 | Enumeration member
222 | Property
223 | Method
224 |
225 |
226 | Interface
227 | Interface with type parameter
228 | Constructor
229 | Property
230 | Method
231 | Index signature
232 |
233 |
234 | Class
235 | Class with type parameter
236 | Constructor
237 | Property
238 | Method
239 | Accessor
240 | Index signature
241 |
242 |
243 | Inherited constructor
244 | Inherited property
245 | Inherited method
246 | Inherited accessor
247 |
248 |
249 | Protected property
250 | Protected method
251 | Protected accessor
252 |
253 |
254 | Private property
255 | Private method
256 | Private accessor
257 |
258 |
259 | Static property
260 | Static method
261 |
262 |
263 |
264 |
265 |
266 |
Generated using TypeDoc
267 |
268 |
269 |
270 |
271 |
272 |
--------------------------------------------------------------------------------
/docs/interfaces/_engine_.engineentitylistener.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EngineEntityListener | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
65 |
Interface EngineEntityListener
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Hierarchy
74 |
75 |
76 | EngineEntityListener
77 |
78 |
79 |
80 |
94 |
95 | Methods
96 |
97 |
98 | onEntityAdded
99 |
100 | onEntityAdded( entity: Entity ) : void
101 |
102 |
103 |
104 |
105 |
106 | Defined in Engine.ts:5
107 |
108 |
109 | Parameters
110 |
115 | Returns void
116 |
117 |
118 |
119 |
120 |
121 | onEntityRemoved
122 |
123 | onEntityRemoved( entity: Entity ) : void
124 |
125 |
126 |
127 |
128 |
129 | Defined in Engine.ts:6
130 |
131 |
132 | Parameters
133 |
138 | Returns void
139 |
140 |
141 |
142 |
143 |
144 |
193 |
194 |
195 |
196 |
197 |
Legend
198 |
199 |
200 | Module
201 | Object literal
202 | Variable
203 | Function
204 | Function with type parameter
205 | Index signature
206 | Type alias
207 |
208 |
209 | Enumeration
210 | Enumeration member
211 | Property
212 | Method
213 |
214 |
215 | Interface
216 | Interface with type parameter
217 | Constructor
218 | Property
219 | Method
220 | Index signature
221 |
222 |
223 | Class
224 | Class with type parameter
225 | Constructor
226 | Property
227 | Method
228 | Accessor
229 | Index signature
230 |
231 |
232 | Inherited constructor
233 | Inherited property
234 | Inherited method
235 | Inherited accessor
236 |
237 |
238 | Protected property
239 | Protected method
240 | Protected accessor
241 |
242 |
243 | Private property
244 | Private method
245 | Private accessor
246 |
247 |
248 | Static property
249 | Static method
250 |
251 |
252 |
253 |
254 |
255 |
Generated using TypeDoc
256 |
257 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/docs/interfaces/_family_.family.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Family | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
65 |
Interface Family
66 |
67 |
68 |
69 |
70 |
71 |
72 |
83 |
84 | Hierarchy
85 |
86 |
87 | Family
88 |
89 |
90 |
91 |
92 | Implemented by
93 |
98 |
99 |
100 | Index
101 |
102 |
103 |
104 | Properties
105 |
108 |
109 |
110 | Methods
111 |
114 |
115 |
116 |
117 |
118 |
119 | Properties
120 |
121 |
122 | entities
123 | entities
: ReadonlyArray < Entity >
124 |
125 |
126 | Defined in Family.ts:17
127 |
128 |
129 |
135 |
136 |
137 |
138 | Methods
139 |
140 |
141 | includesEntity
142 |
143 | includesEntity( entity: Entity ) : boolean
144 |
145 |
146 |
147 |
148 |
149 | Defined in Family.ts:18
150 |
151 |
152 | Parameters
153 |
158 | Returns boolean
159 |
160 |
161 |
162 |
163 |
164 |
222 |
223 |
224 |
225 |
226 |
Legend
227 |
228 |
229 | Module
230 | Object literal
231 | Variable
232 | Function
233 | Function with type parameter
234 | Index signature
235 | Type alias
236 |
237 |
238 | Enumeration
239 | Enumeration member
240 | Property
241 | Method
242 |
243 |
244 | Interface
245 | Interface with type parameter
246 | Constructor
247 | Property
248 | Method
249 | Index signature
250 |
251 |
252 | Class
253 | Class with type parameter
254 | Constructor
255 | Property
256 | Method
257 | Accessor
258 | Index signature
259 |
260 |
261 | Inherited constructor
262 | Inherited property
263 | Inherited method
264 | Inherited accessor
265 |
266 |
267 | Protected property
268 | Protected method
269 | Protected accessor
270 |
271 |
272 | Private property
273 | Private method
274 | Private accessor
275 |
276 |
277 | Static property
278 | Static method
279 |
280 |
281 |
282 |
283 |
284 |
Generated using TypeDoc
285 |
286 |
287 |
288 |
289 |
290 |
--------------------------------------------------------------------------------
/docs/modules/_component_.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "Component" | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
External module "Component"
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Index
71 |
72 |
73 |
74 | Interfaces
75 |
79 |
80 |
81 |
82 |
83 |
84 |
121 |
122 |
123 |
124 |
125 |
Legend
126 |
127 |
128 | Module
129 | Object literal
130 | Variable
131 | Function
132 | Function with type parameter
133 | Index signature
134 | Type alias
135 |
136 |
137 | Enumeration
138 | Enumeration member
139 | Property
140 | Method
141 |
142 |
143 | Interface
144 | Interface with type parameter
145 | Constructor
146 | Property
147 | Method
148 | Index signature
149 |
150 |
151 | Class
152 | Class with type parameter
153 | Constructor
154 | Property
155 | Method
156 | Accessor
157 | Index signature
158 |
159 |
160 | Inherited constructor
161 | Inherited property
162 | Inherited method
163 | Inherited accessor
164 |
165 |
166 | Protected property
167 | Protected method
168 | Protected accessor
169 |
170 |
171 | Private property
172 | Private method
173 | Private accessor
174 |
175 |
176 | Static property
177 | Static method
178 |
179 |
180 |
181 |
182 |
183 |
Generated using TypeDoc
184 |
185 |
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/docs/modules/_engine_.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "Engine" | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
External module "Engine"
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Index
71 |
72 |
73 |
79 |
80 | Interfaces
81 |
84 |
85 |
86 |
87 |
88 |
89 |
126 |
127 |
128 |
129 |
130 |
Legend
131 |
132 |
133 | Module
134 | Object literal
135 | Variable
136 | Function
137 | Function with type parameter
138 | Index signature
139 | Type alias
140 |
141 |
142 | Enumeration
143 | Enumeration member
144 | Property
145 | Method
146 |
147 |
148 | Interface
149 | Interface with type parameter
150 | Constructor
151 | Property
152 | Method
153 | Index signature
154 |
155 |
156 | Class
157 | Class with type parameter
158 | Constructor
159 | Property
160 | Method
161 | Accessor
162 | Index signature
163 |
164 |
165 | Inherited constructor
166 | Inherited property
167 | Inherited method
168 | Inherited accessor
169 |
170 |
171 | Protected property
172 | Protected method
173 | Protected accessor
174 |
175 |
176 | Private property
177 | Private method
178 | Private accessor
179 |
180 |
181 | Static property
182 | Static method
183 |
184 |
185 |
186 |
187 |
188 |
Generated using TypeDoc
189 |
190 |
191 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/docs/modules/_entity_.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "Entity" | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
External module "Entity"
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Index
71 |
72 |
73 |
79 |
80 | Type aliases
81 |
84 |
85 |
86 |
87 |
88 |
89 | Type aliases
90 |
91 |
92 | EntityChangeListener
93 | EntityChangeListener: function
94 |
95 |
96 | Defined in Entity.ts:3
97 |
98 |
99 |
100 |
Type declaration
101 |
102 |
103 |
104 | ( entity: Entity ) : any
105 |
106 |
107 |
108 | Parameters
109 |
114 | Returns any
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
160 |
161 |
162 |
163 |
164 |
Legend
165 |
166 |
167 | Module
168 | Object literal
169 | Variable
170 | Function
171 | Function with type parameter
172 | Index signature
173 | Type alias
174 |
175 |
176 | Enumeration
177 | Enumeration member
178 | Property
179 | Method
180 |
181 |
182 | Interface
183 | Interface with type parameter
184 | Constructor
185 | Property
186 | Method
187 | Index signature
188 |
189 |
190 | Class
191 | Class with type parameter
192 | Constructor
193 | Property
194 | Method
195 | Accessor
196 | Index signature
197 |
198 |
199 | Inherited constructor
200 | Inherited property
201 | Inherited method
202 | Inherited accessor
203 |
204 |
205 | Protected property
206 | Protected method
207 | Protected accessor
208 |
209 |
210 | Private property
211 | Private method
212 | Private accessor
213 |
214 |
215 | Static property
216 | Static method
217 |
218 |
219 |
220 |
221 |
222 |
Generated using TypeDoc
223 |
224 |
225 |
226 |
227 |
228 |
--------------------------------------------------------------------------------
/docs/modules/_family_.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "Family" | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
External module "Family"
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Index
71 |
72 |
73 |
82 |
83 | Interfaces
84 |
87 |
88 |
89 |
90 |
91 |
92 |
138 |
139 |
140 |
141 |
142 |
Legend
143 |
144 |
145 | Module
146 | Object literal
147 | Variable
148 | Function
149 | Function with type parameter
150 | Index signature
151 | Type alias
152 |
153 |
154 | Enumeration
155 | Enumeration member
156 | Property
157 | Method
158 |
159 |
160 | Interface
161 | Interface with type parameter
162 | Constructor
163 | Property
164 | Method
165 | Index signature
166 |
167 |
168 | Class
169 | Class with type parameter
170 | Constructor
171 | Property
172 | Method
173 | Accessor
174 | Index signature
175 |
176 |
177 | Inherited constructor
178 | Inherited property
179 | Inherited method
180 | Inherited accessor
181 |
182 |
183 | Protected property
184 | Protected method
185 | Protected accessor
186 |
187 |
188 | Private property
189 | Private method
190 | Private accessor
191 |
192 |
193 | Static property
194 | Static method
195 |
196 |
197 |
198 |
199 |
200 |
Generated using TypeDoc
201 |
202 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/docs/modules/_index_.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "index" | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
External module "index"
63 |
64 |
65 |
66 |
103 |
104 |
105 |
Legend
106 |
107 |
108 | Module
109 | Object literal
110 | Variable
111 | Function
112 | Function with type parameter
113 | Index signature
114 | Type alias
115 |
116 |
117 | Enumeration
118 | Enumeration member
119 | Property
120 | Method
121 |
122 |
123 | Interface
124 | Interface with type parameter
125 | Constructor
126 | Property
127 | Method
128 | Index signature
129 |
130 |
131 | Class
132 | Class with type parameter
133 | Constructor
134 | Property
135 | Method
136 | Accessor
137 | Index signature
138 |
139 |
140 | Inherited constructor
141 | Inherited property
142 | Inherited method
143 | Inherited accessor
144 |
145 |
146 | Protected property
147 | Protected method
148 | Protected accessor
149 |
150 |
151 | Private property
152 | Private method
153 | Private accessor
154 |
155 |
156 | Static property
157 | Static method
158 |
159 |
160 |
161 |
162 |
163 |
Generated using TypeDoc
164 |
165 |
166 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/docs/modules/_system_.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "System" | @nova-engine/ecs
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Search
19 |
20 |
21 |
22 | Preparing search index...
23 | The search index is not available
24 |
25 |
@nova-engine/ecs
26 |
27 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
External module "System"
63 |
64 |
65 |
66 |
119 |
120 |
121 |
Legend
122 |
123 |
124 | Module
125 | Object literal
126 | Variable
127 | Function
128 | Function with type parameter
129 | Index signature
130 | Type alias
131 |
132 |
133 | Enumeration
134 | Enumeration member
135 | Property
136 | Method
137 |
138 |
139 | Interface
140 | Interface with type parameter
141 | Constructor
142 | Property
143 | Method
144 | Index signature
145 |
146 |
147 | Class
148 | Class with type parameter
149 | Constructor
150 | Property
151 | Method
152 | Accessor
153 | Index signature
154 |
155 |
156 | Inherited constructor
157 | Inherited property
158 | Inherited method
159 | Inherited accessor
160 |
161 |
162 | Protected property
163 | Protected method
164 | Protected accessor
165 |
166 |
167 | Private property
168 | Private method
169 | Private accessor
170 |
171 |
172 | Static property
173 | Static method
174 |
175 |
176 |
177 |
178 |
179 |
Generated using TypeDoc
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./lib/index";
2 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./lib/index");
--------------------------------------------------------------------------------
/lib/Component.d.ts:
--------------------------------------------------------------------------------
1 | interface Component {
2 | }
3 | interface ComponentClass {
4 | readonly name: string;
5 | readonly tag?: string;
6 | new (): T;
7 | }
8 | export { Component, ComponentClass };
9 |
--------------------------------------------------------------------------------
/lib/Component.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | //# sourceMappingURL=Component.js.map
--------------------------------------------------------------------------------
/lib/Component.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"Component.js","sourceRoot":"","sources":["../src/Component.ts"],"names":[],"mappings":""}
--------------------------------------------------------------------------------
/lib/Engine.d.ts:
--------------------------------------------------------------------------------
1 | import { Entity } from "./Entity";
2 | import { System } from "./System";
3 | interface EngineEntityListener {
4 | onEntityAdded(entity: Entity): void;
5 | onEntityRemoved(entity: Entity): void;
6 | }
7 | declare class Engine {
8 | private _entities;
9 | private readonly _entityListeners;
10 | private readonly _systems;
11 | private _systemsNeedSorting;
12 | readonly entities: ReadonlyArray;
13 | notifyPriorityChange(system: System): void;
14 | addEntityListener(listener: EngineEntityListener): this;
15 | removeEntityListener(listener: EngineEntityListener): this;
16 | addEntity(entity: Entity): this;
17 | addEntities(...entities: Entity[]): this;
18 | removeEntity(entity: Entity): void;
19 | removeEntities(...entities: Entity[]): this;
20 | addSystem(system: System): this;
21 | addSystems(...systems: System[]): void;
22 | removeSystem(system: System): this;
23 | removeSystems(...systems: System[]): void;
24 | update(delta: number): void;
25 | }
26 | export { Engine, EngineEntityListener };
27 |
--------------------------------------------------------------------------------
/lib/Engine.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var Engine = (function () {
4 | function Engine() {
5 | this._entities = [];
6 | this._entityListeners = [];
7 | this._systems = [];
8 | this._systemsNeedSorting = false;
9 | }
10 | Object.defineProperty(Engine.prototype, "entities", {
11 | get: function () {
12 | return Object.freeze(this._entities.slice(0));
13 | },
14 | enumerable: true,
15 | configurable: true
16 | });
17 | Engine.prototype.notifyPriorityChange = function (system) {
18 | this._systemsNeedSorting = true;
19 | };
20 | Engine.prototype.addEntityListener = function (listener) {
21 | if (this._entityListeners.indexOf(listener) === -1) {
22 | this._entityListeners.push(listener);
23 | }
24 | return this;
25 | };
26 | Engine.prototype.removeEntityListener = function (listener) {
27 | var index = this._entityListeners.indexOf(listener);
28 | if (index !== -1) {
29 | this._entityListeners.splice(index, 1);
30 | }
31 | return this;
32 | };
33 | Engine.prototype.addEntity = function (entity) {
34 | if (this._entities.indexOf(entity) === -1) {
35 | this._entities.push(entity);
36 | for (var _i = 0, _a = this._entityListeners; _i < _a.length; _i++) {
37 | var listener = _a[_i];
38 | listener.onEntityAdded(entity);
39 | }
40 | }
41 | return this;
42 | };
43 | Engine.prototype.addEntities = function () {
44 | var entities = [];
45 | for (var _i = 0; _i < arguments.length; _i++) {
46 | entities[_i] = arguments[_i];
47 | }
48 | for (var _a = 0, entities_1 = entities; _a < entities_1.length; _a++) {
49 | var entity = entities_1[_a];
50 | this.addEntity(entity);
51 | }
52 | return this;
53 | };
54 | Engine.prototype.removeEntity = function (entity) {
55 | var index = this._entities.indexOf(entity);
56 | if (index !== -1) {
57 | this._entities.splice(index, 1);
58 | for (var _i = 0, _a = this._entityListeners; _i < _a.length; _i++) {
59 | var listener = _a[_i];
60 | listener.onEntityRemoved(entity);
61 | }
62 | }
63 | };
64 | Engine.prototype.removeEntities = function () {
65 | var entities = [];
66 | for (var _i = 0; _i < arguments.length; _i++) {
67 | entities[_i] = arguments[_i];
68 | }
69 | for (var _a = 0, entities_2 = entities; _a < entities_2.length; _a++) {
70 | var entity = entities_2[_a];
71 | this.removeEntity(entity);
72 | }
73 | return this;
74 | };
75 | Engine.prototype.addSystem = function (system) {
76 | var index = this._systems.indexOf(system);
77 | if (index === -1) {
78 | this._systems.push(system);
79 | system.onAttach(this);
80 | this._systemsNeedSorting = true;
81 | }
82 | return this;
83 | };
84 | Engine.prototype.addSystems = function () {
85 | var systems = [];
86 | for (var _i = 0; _i < arguments.length; _i++) {
87 | systems[_i] = arguments[_i];
88 | }
89 | for (var _a = 0, systems_1 = systems; _a < systems_1.length; _a++) {
90 | var system = systems_1[_a];
91 | this.addSystem(system);
92 | }
93 | };
94 | Engine.prototype.removeSystem = function (system) {
95 | var index = this._systems.indexOf(system);
96 | if (index !== -1) {
97 | this._systems.splice(index, 1);
98 | system.onDetach(this);
99 | }
100 | return this;
101 | };
102 | Engine.prototype.removeSystems = function () {
103 | var systems = [];
104 | for (var _i = 0; _i < arguments.length; _i++) {
105 | systems[_i] = arguments[_i];
106 | }
107 | for (var _a = 0, systems_2 = systems; _a < systems_2.length; _a++) {
108 | var system = systems_2[_a];
109 | this.removeSystem(system);
110 | }
111 | };
112 | Engine.prototype.update = function (delta) {
113 | if (this._systemsNeedSorting) {
114 | this._systemsNeedSorting = false;
115 | this._systems.sort(function (a, b) { return a.priority - b.priority; });
116 | }
117 | for (var _i = 0, _a = this._systems; _i < _a.length; _i++) {
118 | var system = _a[_i];
119 | system.update(this, delta);
120 | }
121 | };
122 | return Engine;
123 | }());
124 | exports.Engine = Engine;
125 | //# sourceMappingURL=Engine.js.map
--------------------------------------------------------------------------------
/lib/Engine.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"Engine.js","sourceRoot":"","sources":["../src/Engine.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/lib/Entity.d.ts:
--------------------------------------------------------------------------------
1 | import { ComponentClass, Component } from "./Component";
2 | declare type EntityChangeListener = (entity: Entity) => any;
3 | declare class Entity {
4 | private _id;
5 | private readonly _components;
6 | private readonly _listeners;
7 | private readonly _componentClasses;
8 | id: string | number;
9 | isNew(): boolean;
10 | listComponents(): Component[];
11 | listComponentsWithTypes(): {
12 | component: Component;
13 | type: ComponentClass;
14 | }[];
15 | listComponentsWithTags(): Readonly<{
16 | tag: string;
17 | component: Component;
18 | }>[];
19 | hasComponent(componentClass: ComponentClass): boolean;
20 | getComponent(componentClass: ComponentClass): T;
21 | putComponent(componentClass: ComponentClass): T;
22 | removeComponent(componentClass: ComponentClass): void;
23 | cast(component: Component | undefined | null, componentClass: ComponentClass): component is T;
24 | addListener(listener: EntityChangeListener): this;
25 | removeListener(listener: EntityChangeListener): this;
26 | }
27 | export { Entity, EntityChangeListener };
28 |
--------------------------------------------------------------------------------
/lib/Entity.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var Entity = (function () {
4 | function Entity() {
5 | this._id = null;
6 | this._components = {};
7 | this._listeners = [];
8 | this._componentClasses = {};
9 | }
10 | Object.defineProperty(Entity.prototype, "id", {
11 | get: function () {
12 | if (this._id === null) {
13 | throw new Error("Cannot retrieve an ID when is null.");
14 | }
15 | return this._id;
16 | },
17 | set: function (value) {
18 | if (value === null || value === undefined) {
19 | throw new Error("Must set a non null value when setting an entity id.");
20 | }
21 | if (this._id !== null) {
22 | throw new Error("Entity id is already set as \"" + this._id + "\".");
23 | }
24 | this._id = value;
25 | },
26 | enumerable: true,
27 | configurable: true
28 | });
29 | Entity.prototype.isNew = function () {
30 | return this._id === null;
31 | };
32 | Entity.prototype.listComponents = function () {
33 | var _this = this;
34 | return Object.keys(this._components).map(function (i) { return _this._components[i]; });
35 | };
36 | Entity.prototype.listComponentsWithTypes = function () {
37 | var _this = this;
38 | return Object.keys(this._components).map(function (i) { return ({
39 | component: _this._components[i],
40 | type: _this._componentClasses[i]
41 | }); });
42 | };
43 | Entity.prototype.listComponentsWithTags = function () {
44 | var _this = this;
45 | return Object.keys(this._components).map(function (tag) {
46 | return Object.freeze({
47 | tag: tag,
48 | component: _this._components[tag]
49 | });
50 | });
51 | };
52 | Entity.prototype.hasComponent = function (componentClass) {
53 | var tag = componentClass.tag || componentClass.name;
54 | var component = this._components[tag];
55 | if (!component)
56 | return false;
57 | if (!this.cast(component, componentClass)) {
58 | throw new Error("There are multiple classes with the same tag or name \"" + tag + "\".\nAdd a different property \"tag\" to one of them.");
59 | }
60 | return true;
61 | };
62 | Entity.prototype.getComponent = function (componentClass) {
63 | var tag = componentClass.tag || componentClass.name;
64 | var component = this._components[tag];
65 | if (!component) {
66 | throw new Error("Cannot get component \"" + tag + "\" from entity.");
67 | }
68 | if (!this.cast(component, componentClass)) {
69 | throw new Error("There are multiple classes with the same tag or name \"" + tag + "\".\nAdd a different property \"tag\" to one of them.");
70 | }
71 | return component;
72 | };
73 | Entity.prototype.putComponent = function (componentClass) {
74 | var tag = componentClass.tag || componentClass.name;
75 | var component = this._components[tag];
76 | if (component) {
77 | if (!this.cast(component, componentClass)) {
78 | throw new Error("There are multiple classes with the same tag or name \"" + tag + "\".\nAdd a different property \"tag\" to one of them.");
79 | }
80 | delete this._components[tag];
81 | delete this._componentClasses[tag];
82 | }
83 | var newComponent = new componentClass();
84 | this._components[tag] = newComponent;
85 | this._componentClasses[tag] = componentClass;
86 | for (var _i = 0, _a = this._listeners; _i < _a.length; _i++) {
87 | var listener = _a[_i];
88 | listener(this);
89 | }
90 | return newComponent;
91 | };
92 | Entity.prototype.removeComponent = function (componentClass) {
93 | var tag = componentClass.tag || componentClass.name;
94 | var component = this._components[tag];
95 | if (!component) {
96 | throw new Error("Component of tag \"" + tag + "\".\nDoes not exists.");
97 | }
98 | if (!this.cast(component, componentClass)) {
99 | throw new Error("There are multiple classes with the same tag or name \"" + tag + "\".\nAdd a different property \"tag\" to one of them.");
100 | }
101 | delete this._components[tag];
102 | for (var _i = 0, _a = this._listeners; _i < _a.length; _i++) {
103 | var listener = _a[_i];
104 | listener(this);
105 | }
106 | };
107 | Entity.prototype.cast = function (component, componentClass) {
108 | return !!(component && component instanceof componentClass);
109 | };
110 | Entity.prototype.addListener = function (listener) {
111 | var index = this._listeners.indexOf(listener);
112 | if (index === -1) {
113 | this._listeners.push(listener);
114 | }
115 | return this;
116 | };
117 | Entity.prototype.removeListener = function (listener) {
118 | var index = this._listeners.indexOf(listener);
119 | if (index !== -1) {
120 | this._listeners.splice(index, 1);
121 | }
122 | return this;
123 | };
124 | return Entity;
125 | }());
126 | exports.Entity = Entity;
127 | //# sourceMappingURL=Entity.js.map
--------------------------------------------------------------------------------
/lib/Entity.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"Entity.js","sourceRoot":"","sources":["../src/Entity.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/lib/Family.d.ts:
--------------------------------------------------------------------------------
1 | import { Component, ComponentClass } from "./Component";
2 | import { Engine } from "./Engine";
3 | import { Entity } from "./Entity";
4 | interface Family {
5 | readonly entities: ReadonlyArray;
6 | includesEntity(entity: Entity): boolean;
7 | }
8 | declare class FamilyBuilder {
9 | private _engine;
10 | private _cached;
11 | private readonly _include;
12 | private readonly _exclude;
13 | constructor(engine?: Engine);
14 | include(...classes: ComponentClass[]): this;
15 | exclude(...classes: ComponentClass[]): this;
16 | changeEngine(engine: Engine): this;
17 | setCached(cached: boolean): void;
18 | build(): Family;
19 | }
20 | export { Family, FamilyBuilder };
21 |
--------------------------------------------------------------------------------
/lib/Family.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __extends = (this && this.__extends) || (function () {
3 | var extendStatics = Object.setPrototypeOf ||
4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 | return function (d, b) {
7 | extendStatics(d, b);
8 | function __() { this.constructor = d; }
9 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
10 | };
11 | })();
12 | Object.defineProperty(exports, "__esModule", { value: true });
13 | var AbstractFamily = (function () {
14 | function AbstractFamily(engine, include, exclude) {
15 | var _this = this;
16 | this.includesEntity = function (entity) {
17 | for (var _i = 0, _a = _this._include; _i < _a.length; _i++) {
18 | var include = _a[_i];
19 | if (!entity.hasComponent(include)) {
20 | return false;
21 | }
22 | }
23 | for (var _b = 0, _c = _this._exclude; _b < _c.length; _b++) {
24 | var exclude = _c[_b];
25 | if (entity.hasComponent(exclude)) {
26 | return false;
27 | }
28 | }
29 | return true;
30 | };
31 | this._engine = engine;
32 | this._include = Object.freeze(include.slice(0));
33 | this._exclude = Object.freeze(exclude.slice(0));
34 | }
35 | Object.defineProperty(AbstractFamily.prototype, "engine", {
36 | get: function () {
37 | return this._engine;
38 | },
39 | enumerable: true,
40 | configurable: true
41 | });
42 | return AbstractFamily;
43 | }());
44 | var CachedFamily = (function (_super) {
45 | __extends(CachedFamily, _super);
46 | function CachedFamily(engine, include, exclude) {
47 | var _this = _super.call(this, engine, include, exclude) || this;
48 | _this.onEntityChanged = function (entity) {
49 | var index = _this._entities.indexOf(entity);
50 | if (index === -1) {
51 | _this._entities.push(entity);
52 | entity.addListener(_this.onEntityChanged);
53 | }
54 | _this._needEntityRefresh = true;
55 | };
56 | var allEntities = _this.engine.entities;
57 | _this._entities = allEntities.filter(_this.includesEntity);
58 | _this.engine.addEntityListener(_this);
59 | for (var _i = 0, allEntities_1 = allEntities; _i < allEntities_1.length; _i++) {
60 | var entity = allEntities_1[_i];
61 | entity.addListener(_this.onEntityAdded);
62 | }
63 | _this._needEntityRefresh = false;
64 | return _this;
65 | }
66 | Object.defineProperty(CachedFamily.prototype, "entities", {
67 | get: function () {
68 | if (this._needEntityRefresh) {
69 | this._needEntityRefresh = false;
70 | this._entities = this._entities.filter(this.includesEntity);
71 | }
72 | return Object.freeze(this._entities.slice(0));
73 | },
74 | enumerable: true,
75 | configurable: true
76 | });
77 | CachedFamily.prototype.onEntityAdded = function (entity) {
78 | var index = this._entities.indexOf(entity);
79 | if (index === -1) {
80 | this._entities.push(entity);
81 | this._needEntityRefresh = true;
82 | entity.addListener(this.onEntityChanged);
83 | }
84 | };
85 | CachedFamily.prototype.onEntityRemoved = function (entity) {
86 | var index = this._entities.indexOf(entity);
87 | if (index !== -1) {
88 | var entity_1 = this._entities[index];
89 | this._entities.splice(index, 1);
90 | entity_1.removeListener(this.onEntityChanged);
91 | }
92 | };
93 | return CachedFamily;
94 | }(AbstractFamily));
95 | var NonCachedFamily = (function (_super) {
96 | __extends(NonCachedFamily, _super);
97 | function NonCachedFamily() {
98 | return _super !== null && _super.apply(this, arguments) || this;
99 | }
100 | Object.defineProperty(NonCachedFamily.prototype, "entities", {
101 | get: function () {
102 | return this.engine.entities.filter(this.includesEntity);
103 | },
104 | enumerable: true,
105 | configurable: true
106 | });
107 | return NonCachedFamily;
108 | }(AbstractFamily));
109 | var FamilyBuilder = (function () {
110 | function FamilyBuilder(engine) {
111 | this._engine = engine || null;
112 | this._include = [];
113 | this._exclude = [];
114 | this._cached = true;
115 | }
116 | FamilyBuilder.prototype.include = function () {
117 | var classes = [];
118 | for (var _i = 0; _i < arguments.length; _i++) {
119 | classes[_i] = arguments[_i];
120 | }
121 | (_a = this._include).push.apply(_a, classes);
122 | return this;
123 | var _a;
124 | };
125 | FamilyBuilder.prototype.exclude = function () {
126 | var classes = [];
127 | for (var _i = 0; _i < arguments.length; _i++) {
128 | classes[_i] = arguments[_i];
129 | }
130 | (_a = this._exclude).push.apply(_a, classes);
131 | return this;
132 | var _a;
133 | };
134 | FamilyBuilder.prototype.changeEngine = function (engine) {
135 | this._engine = engine;
136 | return this;
137 | };
138 | FamilyBuilder.prototype.setCached = function (cached) {
139 | this._cached = cached;
140 | };
141 | FamilyBuilder.prototype.build = function () {
142 | if (!this._engine) {
143 | throw new Error("Family should always belong to an engine.");
144 | }
145 | if (!this._cached) {
146 | return new NonCachedFamily(this._engine, this._include, this._exclude);
147 | }
148 | return new CachedFamily(this._engine, this._include, this._exclude);
149 | };
150 | return FamilyBuilder;
151 | }());
152 | exports.FamilyBuilder = FamilyBuilder;
153 | //# sourceMappingURL=Family.js.map
--------------------------------------------------------------------------------
/lib/Family.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"Family.js","sourceRoot":"","sources":["../src/Family.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/lib/System.d.ts:
--------------------------------------------------------------------------------
1 | import { Engine } from "./Engine";
2 | declare abstract class System {
3 | private _priority;
4 | private readonly _engines;
5 | constructor();
6 | priority: number;
7 | readonly engines: ReadonlyArray;
8 | onAttach(engine: Engine): void;
9 | onDetach(engine: Engine): void;
10 | abstract update(engine: Engine, delta: number): void;
11 | }
12 | export { System };
13 |
--------------------------------------------------------------------------------
/lib/System.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | var System = (function () {
4 | function System() {
5 | this._priority = 0;
6 | this._engines = [];
7 | }
8 | Object.defineProperty(System.prototype, "priority", {
9 | get: function () {
10 | return this._priority;
11 | },
12 | set: function (value) {
13 | this._priority = value;
14 | for (var _i = 0, _a = this._engines; _i < _a.length; _i++) {
15 | var engine = _a[_i];
16 | engine.notifyPriorityChange(this);
17 | }
18 | },
19 | enumerable: true,
20 | configurable: true
21 | });
22 | Object.defineProperty(System.prototype, "engines", {
23 | get: function () {
24 | return Object.freeze(this._engines.slice(0));
25 | },
26 | enumerable: true,
27 | configurable: true
28 | });
29 | System.prototype.onAttach = function (engine) {
30 | var index = this._engines.indexOf(engine);
31 | if (index === -1) {
32 | this._engines.push(engine);
33 | }
34 | };
35 | System.prototype.onDetach = function (engine) {
36 | var index = this._engines.indexOf(engine);
37 | if (index !== -1) {
38 | this._engines.splice(index, 1);
39 | }
40 | };
41 | return System;
42 | }());
43 | exports.System = System;
44 | //# sourceMappingURL=System.js.map
--------------------------------------------------------------------------------
/lib/System.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"System.js","sourceRoot":"","sources":["../src/System.ts"],"names":[],"mappings":";;AAEA;IAIE;QACE,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,sBAAI,4BAAQ;aAAZ;YACE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;aAMD,UAAa,KAAa;YACxB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,GAAG,CAAC,CAAe,UAAa,EAAb,KAAA,IAAI,CAAC,QAAQ,EAAb,cAAa,EAAb,IAAa;gBAA3B,IAAI,MAAM,SAAA;gBACb,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;aACnC;QACH,CAAC;;;OAXA;IAED,sBAAI,2BAAO;aAAX;YACE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;;;OAAA;IASD,yBAAQ,GAAR,UAAS,MAAc;QACrB,IAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,yBAAQ,GAAR,UAAS,MAAc;QACrB,IAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACjB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAGH,aAAC;AAAD,CAAC,AAvCD,IAuCC;AAEQ,wBAAM"}
--------------------------------------------------------------------------------
/lib/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from "./Component";
2 | export * from "./Engine";
3 | export * from "./Entity";
4 | export * from "./Family";
5 | export * from "./System";
6 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | function __export(m) {
3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4 | }
5 | Object.defineProperty(exports, "__esModule", { value: true });
6 | __export(require("./Engine"));
7 | __export(require("./Entity"));
8 | __export(require("./Family"));
9 | __export(require("./System"));
10 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AACA,8BAAyB;AACzB,8BAAyB;AACzB,8BAAyB;AACzB,8BAAyB"}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nova-engine/ecs",
3 | "description": "An Entity-Component-System part of the Nova MMO Engine.",
4 | "private": false,
5 | "version": "1.1.1",
6 | "main": "index.js",
7 | "author": {
8 | "name": "Ramiro Rojo",
9 | "email": "ramiro.rojo.cretta@gmail.com"
10 | },
11 | "scripts": {
12 | "precommit": "npm run build && npm run docs && npm test",
13 | "prepush": "npm test",
14 | "test": "mocha -r ts-node/register src/**/*.spec.ts",
15 | "build": "./node_modules/.bin/tsc",
16 | "docs": "typedoc --out docs --mode modules --module commonjs --target es5"
17 | },
18 | "devDependencies": {
19 | "@types/chai": "^4.1.2",
20 | "@types/mocha": "^2.2.48",
21 | "chai": "^4.1.2",
22 | "husky": "^0.14.3",
23 | "mocha": "^5.0.4",
24 | "ts-node": "^5.0.1",
25 | "typedoc": "^0.11.1",
26 | "typescript": "^2.7.2"
27 | },
28 | "repository": {
29 | "type": "git",
30 | "url": "git+https://github.com/nova-engine/ecs.git"
31 | },
32 | "license": "Apache-2.0",
33 | "bugs": {
34 | "url": "https://github.com/nova-engine/ecs/issues"
35 | },
36 | "homepage": "https://github.com/nova-engine/ecs#readme",
37 | "keywords": [
38 | "ecs",
39 | "nova-engine"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/src/Component.ts:
--------------------------------------------------------------------------------
1 | interface Component {}
2 |
3 | interface ComponentClass {
4 | readonly name: string;
5 | readonly tag?: string;
6 | new (): T;
7 | }
8 |
9 | export { Component, ComponentClass };
10 |
--------------------------------------------------------------------------------
/src/Engine.ts:
--------------------------------------------------------------------------------
1 | import { Entity } from "./Entity";
2 | import { System } from "./System";
3 |
4 | interface EngineEntityListener {
5 | onEntityAdded(entity: Entity): void;
6 | onEntityRemoved(entity: Entity): void;
7 | }
8 |
9 | /**
10 | * An engine is the class than combines systems and entities.
11 | * You may have one Engine in your application, but you can make as many as
12 | * you want.
13 | */
14 | class Engine {
15 | /** Private array containing the current list of added entities. */
16 | private _entities: Entity[] = [];
17 | /** Private list of entity listeners */
18 | private readonly _entityListeners: EngineEntityListener[] = [];
19 | /** Private list of added systems. */
20 | private readonly _systems: System[] = [];
21 | /** Checks if the system needs sorting of some sort */
22 | private _systemsNeedSorting: boolean = false;
23 | /**
24 | * Computes an immutable list of entities added to the engine.
25 | */
26 | get entities() {
27 | return Object.freeze(this._entities.slice(0));
28 | }
29 | /**
30 | * Alerts the engine to sort systems by priority.
31 | * @param system The system than changed priority
32 | */
33 | notifyPriorityChange(system: System) {
34 | this._systemsNeedSorting = true;
35 | }
36 |
37 | /**
38 | * Adds a listener for when entities are added or removed.
39 | * @param listener The listener waiting to add
40 | */
41 | addEntityListener(listener: EngineEntityListener) {
42 | if (this._entityListeners.indexOf(listener) === -1) {
43 | this._entityListeners.push(listener);
44 | }
45 | return this;
46 | }
47 |
48 | /**
49 | * Removes a listener from the entity listener list.
50 | * @param listener The listener to remove
51 | */
52 | removeEntityListener(listener: EngineEntityListener) {
53 | const index = this._entityListeners.indexOf(listener);
54 | if (index !== -1) {
55 | this._entityListeners.splice(index, 1);
56 | }
57 | return this;
58 | }
59 |
60 | /**
61 | * Add an entity to the engine.
62 | * The listeners will be notified.
63 | * @param entity The entity to add
64 | */
65 | addEntity(entity: Entity) {
66 | if (this._entities.indexOf(entity) === -1) {
67 | this._entities.push(entity);
68 | for (let listener of this._entityListeners) {
69 | listener.onEntityAdded(entity);
70 | }
71 | }
72 | return this;
73 | }
74 |
75 | /**
76 | * Add a list of entities to the engine.
77 | * The listeners will be notified once per entity.
78 | * @param entities The list of entities to add
79 | */
80 | addEntities(...entities: Entity[]) {
81 | for (let entity of entities) {
82 | this.addEntity(entity);
83 | }
84 | return this;
85 | }
86 |
87 | /**
88 | * Removes an entity to the engine.
89 | * The listeners will be notified.
90 | * @param entity The entity to remove
91 | */
92 | removeEntity(entity: Entity) {
93 | const index = this._entities.indexOf(entity);
94 | if (index !== -1) {
95 | this._entities.splice(index, 1);
96 | for (let listener of this._entityListeners) {
97 | listener.onEntityRemoved(entity);
98 | }
99 | }
100 | }
101 |
102 | /**
103 | * Removes a list of entities to the engine.
104 | * The listeners will be notified once per entity.
105 | * @param entities The list of entities to remove
106 | */
107 | removeEntities(...entities: Entity[]) {
108 | for (let entity of entities) {
109 | this.removeEntity(entity);
110 | }
111 | return this;
112 | }
113 |
114 | /**
115 | * Adds a system to the engine.
116 | * @param system The system to add.
117 | */
118 | addSystem(system: System) {
119 | const index = this._systems.indexOf(system);
120 | if (index === -1) {
121 | this._systems.push(system);
122 | system.onAttach(this);
123 | this._systemsNeedSorting = true;
124 | }
125 | return this;
126 | }
127 |
128 | /**
129 | * Adds a list of systems to the engine.
130 | * @param systems The list of systems to add.
131 | */
132 | addSystems(...systems: System[]) {
133 | for (let system of systems) {
134 | this.addSystem(system);
135 | }
136 | }
137 |
138 | /**
139 | * Removes a system to the engine.
140 | * @param system The system to remove.
141 | */
142 | removeSystem(system: System) {
143 | const index = this._systems.indexOf(system);
144 | if (index !== -1) {
145 | this._systems.splice(index, 1);
146 | system.onDetach(this);
147 | }
148 | return this;
149 | }
150 |
151 | /**
152 | * Removes a list of systems to the engine.
153 | * @param systems The list of systems to remove.
154 | */
155 | removeSystems(...systems: System[]) {
156 | for (let system of systems) {
157 | this.removeSystem(system);
158 | }
159 | }
160 |
161 | /**
162 | * Updates all systems added to the engine.
163 | * @param delta Time elapsed (in milliseconds) since the last update.
164 | */
165 | update(delta: number) {
166 | if (this._systemsNeedSorting) {
167 | this._systemsNeedSorting = false;
168 | this._systems.sort((a, b) => a.priority - b.priority);
169 | }
170 | for (let system of this._systems) {
171 | system.update(this, delta);
172 | }
173 | }
174 | }
175 |
176 | export { Engine, EngineEntityListener };
177 |
--------------------------------------------------------------------------------
/src/Entity.spec.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import "mocha";
3 |
4 | import { Component } from "./Component";
5 |
6 | import { Entity } from "./Entity";
7 |
8 | class MyComponent implements Component {}
9 |
10 | class MyBadTagComponent implements Component {
11 | static readonly tag = "MyComponent";
12 | }
13 |
14 | describe("Entities work", function() {
15 | it("Can only set id once", function() {
16 | const entity = new Entity();
17 | expect(() => entity.id).to.throw();
18 | expect(() => (entity.id = "testing id")).to.not.throw();
19 | expect(() => (entity.id = "other id")).to.throw();
20 | expect(entity.id).to.not.be.equals("other id");
21 | });
22 | it("Can retrieve id when set for the first time", function() {
23 | const entity = new Entity();
24 | expect(() => entity.id).to.throw();
25 | expect(() => (entity.id = "testing id")).to.not.throw();
26 | expect(() => entity.id).to.not.throw();
27 | expect(entity.id).to.be.equals("testing id");
28 | });
29 | it("Can add a component.", function() {
30 | const entity = new Entity();
31 | expect(entity.putComponent(MyComponent)).to.be.instanceof(MyComponent);
32 | expect(() => entity.hasComponent(MyComponent)).to.not.throw();
33 | });
34 | it("Throw error when bad class tags override component types.", function() {
35 | const entity = new Entity();
36 | expect(entity.putComponent(MyComponent)).to.be.instanceof(MyComponent);
37 | expect(() => entity.putComponent(MyBadTagComponent)).to.throw();
38 | });
39 | it("Remove a component.", function() {
40 | const entity = new Entity();
41 | expect(entity.putComponent(MyComponent)).to.be.instanceof(MyComponent);
42 | expect(() => entity.removeComponent(MyComponent)).to.not.throw();
43 | });
44 | it("Throw an error when a bad class tag tries to remove a component.", function() {
45 | const entity = new Entity();
46 | expect(entity.putComponent(MyComponent)).to.be.instanceof(MyComponent);
47 | expect(() => entity.removeComponent(MyBadTagComponent)).to.throw();
48 | });
49 | it("Throw an error when getting a non added component", function() {
50 | const entity = new Entity();
51 | expect(() => entity.getComponent(MyComponent)).to.throw();
52 | });
53 | it("Throw an error when removing a non added component", function() {
54 | const entity = new Entity();
55 | expect(() => entity.removeComponent(MyComponent)).to.throw();
56 | });
57 | });
58 |
--------------------------------------------------------------------------------
/src/Entity.ts:
--------------------------------------------------------------------------------
1 | import { ComponentClass, Component } from "./Component";
2 |
3 | type EntityChangeListener = (entity: Entity) => any;
4 |
5 | /**
6 | * An Entity is every object you may have on your system.
7 | * A character, a weapon, an skill, a map.
8 | * Everything is an Entity.
9 | * Entities are bag of Components, and Components describe how the data exists on
10 | * the entities.
11 | * Entities have an id field that can only be set once and
12 | * will throw when you try to get one when no id is set.
13 | * This set can be used to persist the entity on a database.
14 | */
15 | class Entity {
16 | private _id: string | number | null = null;
17 | private readonly _components: { [tag: string]: Component } = {};
18 | private readonly _listeners: EntityChangeListener[] = [];
19 | private readonly _componentClasses: {
20 | [tag: string]: ComponentClass;
21 | } = {};
22 |
23 | /**
24 | * Gets the id of the entity.
25 | * @throws when the id is null.
26 | */
27 | get id(): string | number {
28 | if (this._id === null) {
29 | throw new Error("Cannot retrieve an ID when is null.");
30 | }
31 | return this._id;
32 | }
33 |
34 | /**
35 | * Sets the id of the entity to a new value.
36 | * @throws when the new value is null or undefined or the id is already set.
37 | */
38 | set id(value: string | number) {
39 | if (value === null || value === undefined) {
40 | throw new Error(`Must set a non null value when setting an entity id.`);
41 | }
42 | if (this._id !== null) {
43 | throw new Error(`Entity id is already set as "${this._id}".`);
44 | }
45 | this._id = value;
46 | }
47 |
48 | /**
49 | * Checks if the entity is newly created.
50 | * An entity is considered new when the id is null.
51 | */
52 | isNew() {
53 | return this._id === null;
54 | }
55 |
56 | /**
57 | * Generates a read only list of components of the entity.
58 | * @returns a list of all components of the entity.
59 | */
60 | listComponents() {
61 | return Object.keys(this._components).map(i => this._components[i]);
62 | }
63 |
64 | /**
65 | * Generates a read only list of components of the entity
66 | * with it's corresponding types.
67 | * @returns a list of all components with types of the entity.
68 | */
69 |
70 | listComponentsWithTypes() {
71 | return Object.keys(this._components).map(i => ({
72 | component: this._components[i],
73 | type: this._componentClasses[i]
74 | }));
75 | }
76 |
77 | /**
78 | * Generates a read only list of components of the entity with it's corresponding tags.
79 | * @returns a list of all components with tags of the entity.
80 | */
81 | listComponentsWithTags() {
82 | return Object.keys(this._components).map(tag =>
83 | Object.freeze({
84 | tag,
85 | component: this._components[tag]
86 | })
87 | );
88 | }
89 |
90 | /**
91 | * Checks if the entity has a component of the specified class.
92 | * @throws if the class than exists on the entity with that tag is different than the asked one.
93 | * @param componentClass The class of the component.
94 | */
95 | hasComponent(componentClass: ComponentClass) {
96 | const tag = componentClass.tag || componentClass.name;
97 | const component = this._components[tag];
98 | if (!component) return false;
99 | if (!this.cast(component, componentClass)) {
100 | throw new Error(
101 | `There are multiple classes with the same tag or name "${tag}".\nAdd a different property "tag" to one of them.`
102 | );
103 | }
104 | return true;
105 | }
106 |
107 | /**
108 | * Returns the component of the specified class.
109 | * @throws if the class than exists on the entity with that tag is different than the asked one.
110 | * @throws if the component is not on the entity.
111 | * @param componentClass The class of the component.
112 | */
113 | getComponent(componentClass: ComponentClass): T {
114 | const tag = componentClass.tag || componentClass.name;
115 | const component = this._components[tag];
116 | if (!component) {
117 | throw new Error(`Cannot get component "${tag}" from entity.`);
118 | }
119 | if (!this.cast(component, componentClass)) {
120 | throw new Error(
121 | `There are multiple classes with the same tag or name "${tag}".\nAdd a different property "tag" to one of them.`
122 | );
123 | }
124 | return component;
125 | }
126 |
127 | /**
128 | * Creates a component of the specified class and adds it to the entity.
129 | * @throws if the class than exists on the entity with that tag is different than the asked one.
130 | * @param componentClass The class of the component.
131 | * @returns The newly created component.
132 | */
133 | putComponent(componentClass: ComponentClass): T {
134 | const tag = componentClass.tag || componentClass.name;
135 | const component = this._components[tag];
136 | if (component) {
137 | if (!this.cast(component, componentClass)) {
138 | throw new Error(
139 | `There are multiple classes with the same tag or name "${tag}".\nAdd a different property "tag" to one of them.`
140 | );
141 | }
142 | delete this._components[tag];
143 | delete this._componentClasses[tag];
144 | }
145 | const newComponent = new componentClass();
146 | this._components[tag] = newComponent;
147 | this._componentClasses[tag] = componentClass;
148 | for (let listener of this._listeners) {
149 | listener(this);
150 | }
151 | return newComponent;
152 | }
153 |
154 | /**
155 | * Removes a component from the entity.
156 | * @throws If the component of that class don't exists on the entity.
157 | * @throws if the class than exists on the entity with that tag is different than the asked one.
158 | * @param componentClass The class of the component.
159 | */
160 | removeComponent(componentClass: ComponentClass) {
161 | const tag = componentClass.tag || componentClass.name;
162 | const component = this._components[tag];
163 | if (!component) {
164 | throw new Error(`Component of tag "${tag}".\nDoes not exists.`);
165 | }
166 | if (!this.cast(component, componentClass)) {
167 | throw new Error(
168 | `There are multiple classes with the same tag or name "${tag}".\nAdd a different property "tag" to one of them.`
169 | );
170 | }
171 | delete this._components[tag];
172 | for (let listener of this._listeners) {
173 | listener(this);
174 | }
175 | }
176 |
177 | /**
178 | * Checks if the component is an instance of the class
179 | * @param component The component to check
180 | * @param componentClass The class to cast into
181 | */
182 | cast(
183 | component: Component | undefined | null,
184 | componentClass: ComponentClass
185 | ): component is T {
186 | return !!(component && component instanceof componentClass);
187 | }
188 |
189 | /**
190 | * Adds a listener to the entity when components are added or removed.
191 | * @param listener The listener to add
192 | */
193 | addListener(listener: EntityChangeListener) {
194 | const index = this._listeners.indexOf(listener);
195 | if (index === -1) {
196 | this._listeners.push(listener);
197 | }
198 | return this;
199 | }
200 |
201 | /**
202 | * Removes a listener from the entity.
203 | * @param listener The listener to remove.
204 | */
205 | removeListener(listener: EntityChangeListener) {
206 | const index = this._listeners.indexOf(listener);
207 | if (index !== -1) {
208 | this._listeners.splice(index, 1);
209 | }
210 | return this;
211 | }
212 | }
213 |
214 | export { Entity, EntityChangeListener };
215 |
--------------------------------------------------------------------------------
/src/Family.spec.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import "mocha";
3 |
4 | import { FamilyBuilder } from "./Family";
5 | import { Engine } from "./Engine";
6 | import { Component } from "./Component";
7 | import { Entity } from "./Entity";
8 |
9 | class MyComponent implements Component {}
10 |
11 | class MyOtherComponent implements Component {}
12 |
13 | describe("Families work", function() {
14 | it("Empty family returns all entities", function() {
15 | const engine = new Engine();
16 | engine.addEntities(new Entity(), new Entity());
17 | const builder = new FamilyBuilder(engine);
18 | const family = builder.build();
19 | expect(family.entities.length).to.be.equals(engine.entities.length);
20 | });
21 | it("Families must always have an Engine attached", function() {
22 | const builder = new FamilyBuilder();
23 | expect(() => builder.build()).to.throw();
24 | });
25 | it("Family includes the corresponding entity for inclusion", function() {
26 | const engine = new Engine();
27 | const entity = new Entity();
28 | entity.putComponent(MyComponent);
29 | entity.putComponent(MyOtherComponent);
30 | engine.addEntities(entity, new Entity());
31 | const builder = new FamilyBuilder(engine);
32 | builder.include(MyComponent, MyOtherComponent);
33 | const family = builder.build();
34 | expect(family.entities.indexOf(entity)).to.not.be.equals(-1);
35 | expect(family.entities.length).to.not.be.equals(engine.entities.length);
36 | expect(family.entities.length).to.not.be.equals(0);
37 | });
38 | it("Family includes the corresponding entity for exclusion", function() {
39 | const engine = new Engine();
40 | const entity = new Entity();
41 | entity.putComponent(MyComponent);
42 | engine.addEntities(entity, new Entity());
43 | const builder = new FamilyBuilder(engine);
44 | builder.exclude(MyComponent);
45 | const family = builder.build();
46 | expect(family.entities.indexOf(entity)).to.be.equals(-1);
47 | expect(family.entities.length).to.not.be.equals(engine.entities.length);
48 | expect(family.entities.length).to.not.be.equals(0);
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/src/Family.ts:
--------------------------------------------------------------------------------
1 | import { Component, ComponentClass } from "./Component";
2 | import { Engine, EngineEntityListener } from "./Engine";
3 | import { Entity } from "./Entity";
4 |
5 | /**
6 | * A family is a criteria to separate your entities.
7 | * You can have families on wich entities must have a component,
8 | * entities cannot have some components or a mix of both.
9 | * Families also cache the entities of the engine by default,
10 | * so you won't have to worry about filtering entities every time.
11 | */
12 | interface Family {
13 | /**
14 | * Computes a list of entities on the family.
15 | * The list may or may not be cached, depending of implementation.
16 | */
17 | readonly entities: ReadonlyArray;
18 | includesEntity(entity: Entity): boolean;
19 | }
20 |
21 | /**
22 | * An abstract family is the base implementation of a family interface.
23 | * This class is private to this module.
24 | * @private
25 | */
26 | abstract class AbstractFamily implements Family {
27 | private readonly _engine: Engine;
28 | private readonly _include: ReadonlyArray>;
29 | private readonly _exclude: ReadonlyArray>;
30 |
31 | constructor(
32 | engine: Engine,
33 | include: ComponentClass[],
34 | exclude: ComponentClass[]
35 | ) {
36 | this._engine = engine;
37 | this._include = Object.freeze(include.slice(0));
38 | this._exclude = Object.freeze(exclude.slice(0));
39 | }
40 |
41 | get engine() {
42 | return this._engine;
43 | }
44 |
45 | abstract readonly entities: ReadonlyArray;
46 |
47 | includesEntity = (entity: Entity) => {
48 | for (let include of this._include) {
49 | if (!entity.hasComponent(include)) {
50 | return false;
51 | }
52 | }
53 | for (let exclude of this._exclude) {
54 | if (entity.hasComponent(exclude)) {
55 | return false;
56 | }
57 | }
58 | return true;
59 | };
60 | }
61 |
62 | /**
63 | * A CachedFamily is a family than caches it's results and alters it only
64 | * when an entity changes.
65 | *
66 | */
67 | class CachedFamily extends AbstractFamily {
68 | private _needEntityRefresh: boolean;
69 | private _entities: Entity[];
70 |
71 | constructor(
72 | engine: Engine,
73 | include: ComponentClass[],
74 | exclude: ComponentClass[]
75 | ) {
76 | super(engine, include, exclude);
77 | const allEntities = this.engine.entities;
78 | this._entities = allEntities.filter(this.includesEntity);
79 | this.engine.addEntityListener(this);
80 | for (let entity of allEntities) {
81 | entity.addListener(this.onEntityAdded);
82 | }
83 | this._needEntityRefresh = false;
84 | }
85 |
86 | get entities() {
87 | if (this._needEntityRefresh) {
88 | this._needEntityRefresh = false;
89 | this._entities = this._entities.filter(this.includesEntity);
90 | }
91 | return Object.freeze(this._entities.slice(0));
92 | }
93 |
94 | onEntityAdded(entity: Entity) {
95 | const index = this._entities.indexOf(entity);
96 | if (index === -1) {
97 | this._entities.push(entity);
98 | this._needEntityRefresh = true;
99 | entity.addListener(this.onEntityChanged);
100 | }
101 | }
102 |
103 | onEntityRemoved(entity: Entity) {
104 | const index = this._entities.indexOf(entity);
105 | if (index !== -1) {
106 | const entity = this._entities[index];
107 | this._entities.splice(index, 1);
108 | entity.removeListener(this.onEntityChanged);
109 | }
110 | }
111 |
112 | onEntityChanged = (entity: Entity) => {
113 | const index = this._entities.indexOf(entity);
114 | if (index === -1) {
115 | this._entities.push(entity);
116 | entity.addListener(this.onEntityChanged);
117 | }
118 | this._needEntityRefresh = true;
119 | };
120 | }
121 |
122 | /**
123 | * A NonCacheFamily always computes the members of it.
124 | * If you find than the performance from cached families is not decent.
125 | * You can use this instead.
126 | * @private
127 | */
128 | class NonCachedFamily extends AbstractFamily {
129 | get entities() {
130 | return this.engine.entities.filter(this.includesEntity);
131 | }
132 | }
133 |
134 | /**
135 | * Utility class to build Families.
136 | * It's the only way to create the implementations of CachedFamily and NonCachedFamily.
137 | */
138 | class FamilyBuilder {
139 | private _engine: Engine | null;
140 | private _cached: boolean;
141 | private readonly _include: ComponentClass[];
142 | private readonly _exclude: ComponentClass[];
143 |
144 | constructor(engine?: Engine) {
145 | this._engine = engine || null;
146 | this._include = [];
147 | this._exclude = [];
148 | this._cached = true;
149 | }
150 |
151 | /**
152 | * Indicates than entities than are members of this class MUST
153 | * HAVE this components.
154 | * @param classes A list of component classes.
155 | */
156 | include(...classes: ComponentClass[]) {
157 | this._include.push(...classes);
158 | return this;
159 | }
160 | /**
161 | * Indicates than entities than are members of this class MUST NOT
162 | * HAVE this components.
163 | * @param classes A list of component classes.
164 | */
165 | exclude(...classes: ComponentClass[]) {
166 | this._exclude.push(...classes);
167 | return this;
168 | }
169 |
170 | /**
171 | * Changes the engine of the builder.
172 | * Useful to create multiple instances of the same family for different
173 | * engines.
174 | * @param engine
175 | */
176 | changeEngine(engine: Engine) {
177 | this._engine = engine;
178 | return this;
179 | }
180 |
181 | /**
182 | * Changes if the family should use cached values or not.
183 | * @param cached If the family must use or not a cache.
184 | */
185 | setCached(cached: boolean) {
186 | this._cached = cached;
187 | }
188 |
189 | /**
190 | * Builds the family, using the information provided.
191 | * @returns a new family to retrieve the entities.
192 | */
193 | build(): Family {
194 | if (!this._engine) {
195 | throw new Error("Family should always belong to an engine.");
196 | }
197 | if (!this._cached) {
198 | return new NonCachedFamily(this._engine, this._include, this._exclude);
199 | }
200 | return new CachedFamily(this._engine, this._include, this._exclude);
201 | }
202 | }
203 |
204 | export { Family, FamilyBuilder };
205 |
--------------------------------------------------------------------------------
/src/System.spec.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import "mocha";
3 |
4 | import { System } from "./System";
5 | import { Engine } from "./Engine";
6 | import { Family, FamilyBuilder } from "./Family";
7 |
8 | class MySystem extends System {
9 | public family: Family | null = null;
10 |
11 | onAttach(engine: Engine) {
12 | super.onAttach(engine);
13 | this.family = new FamilyBuilder(engine).build();
14 | }
15 |
16 | onDetach(engine: Engine) {
17 | super.onDetach(engine);
18 | this.family = null;
19 | }
20 |
21 | update(engine: Engine, delta: number) {}
22 | }
23 |
24 | describe("Systems works", function() {
25 | it("Can be extended", function() {
26 | expect(new MySystem()).to.be.instanceof(System);
27 | expect(new MySystem()).to.be.instanceof(MySystem);
28 | });
29 | it("Attached systems should call the onAttach method", () => {
30 | const engine = new Engine();
31 | const system = new MySystem();
32 | engine.addSystem(system);
33 | expect(system.family).to.not.be.equals(null);
34 | });
35 | it("Detached systems should call the onDetach method", () => {
36 | const engine = new Engine();
37 | const system = new MySystem();
38 | engine.addSystem(system);
39 | engine.removeSystem(system);
40 | expect(system.family).to.be.equals(null);
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/src/System.ts:
--------------------------------------------------------------------------------
1 | import { Engine } from "./Engine";
2 |
3 | abstract class System {
4 | private _priority: number;
5 | private readonly _engines: Engine[];
6 |
7 | constructor() {
8 | this._priority = 0;
9 | this._engines = [];
10 | }
11 |
12 | get priority() {
13 | return this._priority;
14 | }
15 |
16 | get engines() {
17 | return Object.freeze(this._engines.slice(0));
18 | }
19 |
20 | set priority(value: number) {
21 | this._priority = value;
22 | for (let engine of this._engines) {
23 | engine.notifyPriorityChange(this);
24 | }
25 | }
26 |
27 | onAttach(engine: Engine) {
28 | const index = this._engines.indexOf(engine);
29 | if (index === -1) {
30 | this._engines.push(engine);
31 | }
32 | }
33 |
34 | onDetach(engine: Engine) {
35 | const index = this._engines.indexOf(engine);
36 | if (index !== -1) {
37 | this._engines.splice(index, 1);
38 | }
39 | }
40 |
41 | abstract update(engine: Engine, delta: number): void;
42 | }
43 |
44 | export { System };
45 |
--------------------------------------------------------------------------------
/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { expect } from "chai";
2 | import "mocha";
3 |
4 | import * as lib from "./index";
5 |
6 | import { Engine } from "./Engine";
7 | import { Entity } from "./Entity";
8 | import { FamilyBuilder } from "./Family";
9 | import { System } from "./System";
10 |
11 | describe("Modules are exported", function() {
12 | it("Engine is exported", function() {
13 | expect(lib.Engine).to.equal(Engine);
14 | expect(lib.Engine).to.not.be.null;
15 | expect(lib.Engine).to.not.be.undefined;
16 | });
17 | it("Entity is exported", function() {
18 | expect(lib.Entity).to.equal(Entity);
19 | expect(lib.Entity).to.not.be.null;
20 | expect(lib.Entity).to.not.be.undefined;
21 | });
22 | it("FamilyBuilder is exported", function() {
23 | expect(lib.FamilyBuilder).to.equal(FamilyBuilder);
24 | expect(lib.FamilyBuilder).to.not.be.null;
25 | expect(lib.FamilyBuilder).to.not.be.undefined;
26 | });
27 | it("System is exported", function() {
28 | expect(lib.System).to.equal(System);
29 | expect(lib.System).to.not.be.null;
30 | expect(lib.System).to.not.be.undefined;
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./Component";
2 | export * from "./Engine";
3 | export * from "./Entity";
4 | export * from "./Family";
5 | export * from "./System";
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "CommonJS",
5 | "noImplicitAny": true,
6 | "strictNullChecks": true,
7 | "removeComments": true,
8 | "preserveConstEnums": true,
9 | "outDir": "lib",
10 | "sourceMap": true,
11 | "declaration": true,
12 | "lib": ["es5", "es2015.promise", "dom"]
13 | },
14 | "include": ["src/**/*"],
15 | "exclude": ["node_modules", "**/*.spec.ts"]
16 | }
17 |
--------------------------------------------------------------------------------
A family is a criteria to separate your entities. 76 | You can have families on wich entities must have a component, 77 | entities cannot have some components or a mix of both. 78 | Families also cache the entities of the engine by default, 79 | so you won't have to worry about filtering entities every time.
80 |