]> git.r.bdr.sh - rbdr/serpentity/blob - lib/serpentity/serpentity.js
Prepare it for the browser
[rbdr/serpentity] / lib / serpentity / serpentity.js
1 if (typeof require !== "undefined") {
2 require("neon");
3 }
4
5 /*
6 Serpentity is a simple entity framework inspired by Ash.
7
8 Usage:
9
10 require('serpentity');
11
12 ## Instantiating an engine
13
14 var engine = Serpentity();
15
16 Add entities or systems, systems are added with a priority (the smaller
17 the number, the earlier it will be called):
18
19 engine.addEntity(entityFactory());
20 engine.addSystem(new GameSystem(), priority);
21
22 Update all systems:
23
24 engine.update(dt);
25
26 Remove entities or systems:
27
28 engine.removeEntity(entityReference);
29 engine.removeSystem(systemReference);
30
31 ## Creating Entities
32
33 Entities are the basic object of Serpentity, and they do nothing.
34
35 var entity = new Serpentity.Entity();
36
37 All the behavior is added through components
38
39 ## Creating Components
40
41 Components define data that we can add to an entity. This data will
42 eventually be consumed by "Systems"
43
44 Class("PositionComponent").inherits(Serpentity.Component)({
45 prototype : {
46 x : 0,
47 y : 0
48 }
49 });
50
51 You can add components to entities by using the add method:
52
53 entity.add(new PositionComponent());
54
55
56 Systems can refer to entities by requesting nodes.
57
58 ## Working with Nodes
59
60 Nodes are sets of components that you define, so your system can require
61 entities that always follow the API defined in the node.
62
63 Class("MovementNode").inherits(Serpentity.Node)({
64 types : {
65 position : PositionComponent,
66 motion : MotionComponent
67 }
68 });
69
70 You can then request an array of all the nodes representing entities
71 that comply with that API
72
73 engine.getNodes(MovementNode);
74
75 ## Creating Systems
76
77 Systems are called on every update, and they use components through nodes.
78
79 Class("TestSystem").inherits(Serpentity.System)({
80 prototype : {
81 added : function added(engine){
82 this.nodeList = engine.getNodes(MovementNode);
83 },
84 removed : function removed(engine){
85 this.nodeList = undefined;
86 }
87 update : function update(dt){
88 this.nodeList.forEach(function (node) {
89 console.log("Current position is: " + node.position.x + "," + node.position.y);
90 });
91 }
92 }
93 });
94
95 ## That's it
96
97 Just run `engine.update(dt)` in your game loop :D
98
99 */
100 Class("Serpentity")({
101 prototype : {
102 systems : null,
103 nodeCollections : null,
104 entities : null,
105
106 init : function init(config) {
107 var property;
108
109 config = config || {};
110
111 this.systems = [];
112 this.entities = [];
113 this.nodeCollections = {};
114
115 for (property in config) {
116 if (config.hasOwnProperty(property)) {
117 this[property] = config[property];
118 }
119 }
120 },
121
122 /*
123 * Adds a system to the engine, so its update method will be called
124 * with the others. Triggers added hook.
125 *
126 * returns true if added succesfully, false if already added
127 */
128 addSystem : function addSystem(system, priority) {
129 var lastIndex, found;
130
131 if (this.systems.indexOf(system) >= 0) {
132 return false;
133 }
134
135 system.priority = priority;
136
137 found = false;
138 lastIndex = 0;
139
140 this.systems.some(function findPriority(existingSystem, i) {
141 lastIndex = i;
142 if (existingSystem.priority >= system.priority) {
143 found = true;
144 return true;
145 }
146 });
147
148 if (!found) {
149 lastIndex += 1
150 }
151
152 this.systems.splice(lastIndex, 0, system);
153 system.added(this);
154 return true;
155 },
156
157 /*
158 * Removes a system from the engine, so its update method will no
159 * longer will be called. Triggers the removed hook.
160 *
161 * returns true if removed succesfully, false if already added
162 */
163 removeSystem : function removeSystem(system) {
164 var position;
165
166 position = this.systems.indexOf(system);
167 if (position >= 0) {
168 this.systems[position].removed(this);
169 this.systems.splice(position, 1);
170 return true;
171 }
172
173 return false;
174 },
175
176 /*
177 * Adds an entity to the engine, adds to existing node collections
178 *
179 * returns true if added, false if already there
180 */
181 addEntity : function addEntity(entity) {
182 var property;
183
184 if (this.entities.indexOf(entity) >= 0) {
185 return false;
186 }
187 this.entities.push(entity);
188
189 for (property in this.nodeCollections) {
190 if (this.nodeCollections.hasOwnProperty(property)) {
191 this.nodeCollections[property].add(entity);
192 }
193 }
194 return true;
195 },
196
197 /*
198 * Removes entity from system, removing from all node collections
199 *
200 * returns true if removed, false if not present
201 */
202 removeEntity : function removeEntity(entity) {
203 var position;
204
205 position = this.entities.indexOf(entity);
206 if (position >= 0) {
207 for (property in this.nodeCollections) {
208 if (this.nodeCollections.hasOwnProperty(property)) {
209 this.nodeCollections[property].remove(entity);
210 }
211 }
212
213 this.entities.splice(position, 1);
214 return true;
215 }
216
217 return false;
218 },
219
220 /*
221 * Given a Node Class, retrieves a list of all the nodes for each
222 * applicable entity.
223 */
224 getNodes : function getNodes(nodeType) {
225 var nodeCollection;
226
227 if (this.nodeCollections.hasOwnProperty(nodeType)) {
228 return this.nodeCollections[nodeType].nodes;
229 }
230
231 nodeCollection = new Serpentity.NodeCollection({
232 type : nodeType,
233 });
234 this.nodeCollections[nodeType] = nodeCollection;
235
236 this.entities.forEach(function (entity) {
237 nodeCollection.add(entity);
238 });
239
240 return nodeCollection.nodes;
241 },
242
243 /*
244 * Calls update for every loaded system.
245 */
246 update : function update(dt) {
247 this.systems.forEach(function (system) {
248 system.update(dt);
249 });
250 }
251 }
252 });
253
254 if (typeof require !== "undefined") {
255 require("./component.js");
256 require("./entity.js");
257 require("./node.js");
258 require("./node_collection.js");
259 require("./system.js");
260 }