]>
git.r.bdr.sh - rbdr/serpentity/blob - dist/serpentity.js
1 if (typeof require
!== "undefined") {
6 Serpentity is a simple entity framework inspired by Ash.
10 require('serpentity');
12 ## Instantiating an engine
14 var engine = Serpentity();
16 Add entities or systems, systems are added with a priority (the smaller
17 the number, the earlier it will be called):
19 engine.addEntity(entityFactory());
20 engine.addSystem(new GameSystem(), priority);
26 Remove entities or systems:
28 engine.removeEntity(entityReference);
29 engine.removeSystem(systemReference);
33 Entities are the basic object of Serpentity, and they do nothing.
35 var entity = new Serpentity.Entity();
37 All the behavior is added through components
39 ## Creating Components
41 Components define data that we can add to an entity. This data will
42 eventually be consumed by "Systems"
44 Class("PositionComponent").inherits(Serpentity.Component)({
51 You can add components to entities by using the add method:
53 entity.addComponent(new PositionComponent());
56 Systems can refer to entities by requesting nodes.
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.
63 Class("MovementNode").inherits(Serpentity.Node)({
65 position : PositionComponent,
66 motion : MotionComponent
70 You can then request an array of all the nodes representing entities
71 that comply with that API
73 engine.getNodes(MovementNode);
77 Systems are called on every update, and they use components through nodes.
79 Class("TestSystem").inherits(Serpentity.System)({
81 added : function added(engine){
82 this.nodeList = engine.getNodes(MovementNode);
84 removed : function removed(engine){
85 this.nodeList = undefined;
87 update : function update(dt){
88 this.nodeList.forEach(function (node) {
89 console.log("Current position is: " + node.position.x + "," + node.position.y);
97 Just run `engine.update(dt)` in your game loop :D
100 Class("Serpentity")({
104 _nodeCollections : null,
105 _nodeCollectionKeys : null,
107 init : function init(config
) {
110 config
= config
|| {};
114 this._nodeCollections
= [];
115 this._nodeCollectionKeys
= [];
117 for (property
in config
) {
118 if (config
.hasOwnProperty(property
)) {
119 this[property
] = config
[property
];
125 * Adds a system to the engine, so its update method will be called
126 * with the others. Triggers added hook.
128 * returns true if added succesfully, false if already added
130 addSystem : function addSystem(system
, priority
) {
131 var lastIndex
, found
;
133 if (this.systems
.indexOf(system
) >= 0) {
137 system
.priority
= priority
;
142 this.systems
.some(function findPriority(existingSystem
, i
) {
144 if (existingSystem
.priority
>= system
.priority
) {
154 this.systems
.splice(lastIndex
, 0, system
);
160 * Removes a system from the engine, so its update method will no
161 * longer will be called. Triggers the removed hook.
163 * returns true if removed succesfully, false if already added
165 removeSystem : function removeSystem(system
) {
168 position
= this.systems
.indexOf(system
);
170 this.systems
[position
].removed(this);
171 this.systems
.splice(position
, 1);
179 * Adds an entity to the engine, adds to existing node collections
181 * returns true if added, false if already there
183 addEntity : function addEntity(entity
) {
184 if (this.entities
.indexOf(entity
) >= 0) {
187 this.entities
.push(entity
);
189 this._nodeCollections
.forEach(function (collection
) {
190 collection
.add(entity
);
197 * Removes entity from system, removing from all node collections
199 * returns true if removed, false if not present
201 removeEntity : function removeEntity(entity
) {
204 position
= this.entities
.indexOf(entity
);
206 this._nodeCollections
.forEach(function (collection
) {
207 collection
.remove(entity
);
210 this.entities
.splice(position
, 1);
218 * Given a Node Class, retrieves a list of all the nodes for each
221 getNodes : function getNodes(nodeType
) {
222 var position
, nodeCollection
;
224 position
= this._nodeCollectionKeys
.indexOf(nodeType
);
227 return this._nodeCollections
[position
].nodes
;
230 nodeCollection
= new Serpentity
.NodeCollection({
234 this._nodeCollectionKeys
.push(nodeType
);
235 this._nodeCollections
.push(nodeCollection
);
237 this.entities
.forEach(function (entity
) {
238 nodeCollection
.add(entity
);
241 return nodeCollection
.nodes
;
245 * Calls update for every loaded system.
247 update : function update(dt
) {
248 this.systems
.forEach(function (system
) {
255 if (typeof require
!== "undefined") {
256 require("./component.js");
257 require("./entity.js");
258 require("./node.js");
259 require("./node_collection.js");
260 require("./system.js");
264 * The entity gives the entity framework its name. It exists only
265 * to hold components.
267 Class(Serpentity
, "Entity")({
270 _componentKeys : null,
272 init : function init(config
) {
275 this._componentKeys
= [];
276 this._components
= [];
278 for (property
in config
) {
279 if (config
.hasOwnProperty(property
)) {
280 this[property
] = config
[property
];
286 * Adds a component to the entity.
288 * returns true if added, false if already present
290 addComponent : function addComponent(component
) {
291 if (this._componentKeys
.indexOf(component
.constructor) >= 0) {
294 this._componentKeys
.push(component
.constructor);
295 this._components
.push(component
);
300 * returns true if component is included, false otherwise
302 hasComponent : function hasComponent(componentClass
) {
303 if (this._componentKeys
.indexOf(componentClass
) >= 0) {
310 * returns the component associated with that key
312 getComponent : function getComponent(componentClass
) {
314 position
= this._componentKeys
.indexOf(componentClass
);
316 return this._components
[position
];
323 * A node describes a set of components in order to describe entities
326 Class(Serpentity
, "Node")({
329 * Returns true if the given entity matches the defined protocol,
332 matches : function matches(entity
) {
333 var property
, matched
, types
;
337 for (property
in this.types
) {
339 if (this.types
.hasOwnProperty(property
)) {
342 if (entity
.hasComponent(types
[property
])) {
359 init : function (config
) {
364 for (property
in this.constructor) {
365 if (this.constructor.hasOwnProperty(property
)) {
366 this.types
[property
] = this.constructor[property
];
374 * Node Collections contain nodes, in order to keep the lists of nodes
375 * that belong to each type.
377 * It has a type which is the class name of the node, and an array of
378 * instances of that class.
380 Class(Serpentity
, "NodeCollection")({
385 init : function init(config
) {
388 config
= config
|| {};
392 for (property
in config
) {
393 if (config
.hasOwnProperty(property
)) {
394 this[property
] = config
[property
];
400 * Creates a node for an entity if it matches, and adds it to the
403 * Returns true if added, false otherwise.
405 add : function add(entity
) {
406 var node
, types
, property
;
408 if (this.type
.matches(entity
) && !this._entityExists(entity
)) {
409 node
= new this.type({});
411 node
.entity
= entity
;
413 types
= this.type
.types
;
415 for (property
in types
) {
416 if (types
.hasOwnProperty(property
)) {
417 node
[property
] = entity
.getComponent(types
[property
]);
421 this.nodes
.push(node
);
430 * Removes an entity by removing its related node from the list of nodes
432 * returns true if it was removed, false otherwise.
434 remove : function (entity
) {
437 this.nodes
.forEach(function (node
, i
) {
438 if (node
.entity
=== entity
) {
444 this.nodes
.splice(found
, 1);
452 * Checks whether we already have nodes for this entity.
454 _entityExists : function entityExists(entity
) {
457 this.nodes
.forEach(function (node
) {
458 if (node
.entity
=== entity
) {
469 * Components store data. Nothing to say here really, just
470 * inherit and add a prototype, or don't even inherit, see?
471 * It's just an empty class, so what I'm trying to say is your
472 * components can be any class whatsoever.
474 Class(Serpentity
, "Component")({
476 init : function init(config
) {
479 config
= config
|| {};
481 for (property
in config
) {
482 if (config
.hasOwnProperty(property
)) {
483 this[property
] = config
[property
];
491 * Systems contain most of the logic, and work with nodes in order to
492 * act and change their values.
494 * You usually want to inherit from this class and override the
497 Class(Serpentity
, "System")({
501 * This will be run when the system is added to the engine
503 added : function added(engine
) {
508 * This will be run when the system is removed from the engine
510 removed : function removed(engine
) {
515 * This will run every time the engine's update method is called
517 update : function update(dt
) {