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