X-Git-Url: https://git.r.bdr.sh/rbdr/serpentity/blobdiff_plain/a2949b6a6621627d0382fd1702d067b7b82322ed..90acf9e63b09882525fa5a58872a172b585b46fc:/dist/serpentity.js diff --git a/dist/serpentity.js b/dist/serpentity.js index 2f91c25..e57efd5 100644 --- a/dist/serpentity.js +++ b/dist/serpentity.js @@ -1,509 +1 @@ -if (typeof require !== "undefined") { - require("neon"); -} - -/* -Serpentity is a simple entity framework inspired by Ash. - -Usage: - - require('serpentity'); - -## Instantiating an engine - - var engine = Serpentity(); - -Add entities or systems, systems are added with a priority (the smaller -the number, the earlier it will be called): - - engine.addEntity(entityFactory()); - engine.addSystem(new GameSystem(), priority); - -Update all systems: - - engine.update(dt); - -Remove entities or systems: - - engine.removeEntity(entityReference); - engine.removeSystem(systemReference); - -## Creating Entities - -Entities are the basic object of Serpentity, and they do nothing. - - var entity = new Serpentity.Entity(); - -All the behavior is added through components - -## Creating Components - -Components define data that we can add to an entity. This data will -eventually be consumed by "Systems" - - Class("PositionComponent").inherits(Serpentity.Component)({ - prototype : { - x : 0, - y : 0 - } - }); - -You can add components to entities by using the add method: - - entity.add(new PositionComponent()); - - -Systems can refer to entities by requesting nodes. - -## Working with Nodes - -Nodes are sets of components that you define, so your system can require -entities that always follow the API defined in the node. - - Class("MovementNode").inherits(Serpentity.Node)({ - types : { - position : PositionComponent, - motion : MotionComponent - } - }); - -You can then request an array of all the nodes representing entities -that comply with that API - - engine.getNodes(MovementNode); - -## Creating Systems - -Systems are called on every update, and they use components through nodes. - - Class("TestSystem").inherits(Serpentity.System)({ - prototype : { - added : function added(engine){ - this.nodeList = engine.getNodes(MovementNode); - }, - removed : function removed(engine){ - this.nodeList = undefined; - } - update : function update(dt){ - this.nodeList.forEach(function (node) { - console.log("Current position is: " + node.position.x + "," + node.position.y); - }); - } - } - }); - -## That's it - -Just run `engine.update(dt)` in your game loop :D - -*/ -Class("Serpentity")({ - prototype : { - systems : null, - entities : null, - _nodeCollections : null, - _nodeCollectionKeys : null, - - init : function init(config) { - var property; - - config = config || {}; - - this.systems = []; - this.entities = []; - this._nodeCollections = []; - this._nodeCollectionKeys = []; - - for (property in config) { - if (config.hasOwnProperty(property)) { - this[property] = config[property]; - } - } - }, - - /* - * Adds a system to the engine, so its update method will be called - * with the others. Triggers added hook. - * - * returns true if added succesfully, false if already added - */ - addSystem : function addSystem(system, priority) { - var lastIndex, found; - - if (this.systems.indexOf(system) >= 0) { - return false; - } - - system.priority = priority; - - found = false; - lastIndex = 0; - - this.systems.some(function findPriority(existingSystem, i) { - lastIndex = i; - if (existingSystem.priority >= system.priority) { - found = true; - return true; - } - }); - - if (!found) { - lastIndex += 1 - } - - this.systems.splice(lastIndex, 0, system); - system.added(this); - return true; - }, - - /* - * Removes a system from the engine, so its update method will no - * longer will be called. Triggers the removed hook. - * - * returns true if removed succesfully, false if already added - */ - removeSystem : function removeSystem(system) { - var position; - - position = this.systems.indexOf(system); - if (position >= 0) { - this.systems[position].removed(this); - this.systems.splice(position, 1); - return true; - } - - return false; - }, - - /* - * Adds an entity to the engine, adds to existing node collections - * - * returns true if added, false if already there - */ - addEntity : function addEntity(entity) { - if (this.entities.indexOf(entity) >= 0) { - return false; - } - this.entities.push(entity); - - this._nodeCollections.forEach(function (collection) { - collection.add(entity); - }); - - return true; - }, - - /* - * Removes entity from system, removing from all node collections - * - * returns true if removed, false if not present - */ - removeEntity : function removeEntity(entity) { - var position; - - position = this.entities.indexOf(entity); - if (position >= 0) { - this._nodeCollections.forEach(function (collection) { - collection.remove(entity); - }); - - this.entities.splice(position, 1); - return true; - } - - return false; - }, - - /* - * Given a Node Class, retrieves a list of all the nodes for each - * applicable entity. - */ - getNodes : function getNodes(nodeType) { - var position, nodeCollection; - - position = this._nodeCollectionKeys.indexOf(nodeType); - - if (position >= 0) { - return this._nodeCollections[position].nodes; - } - - nodeCollection = new Serpentity.NodeCollection({ - type : nodeType, - }); - - this._nodeCollectionKeys.push(nodeType); - this._nodeCollections.push(nodeCollection); - - this.entities.forEach(function (entity) { - nodeCollection.add(entity); - }); - - return nodeCollection.nodes; - }, - - /* - * Calls update for every loaded system. - */ - update : function update(dt) { - this.systems.forEach(function (system) { - system.update(dt); - }); - } - } -}); - -if (typeof require !== "undefined") { - require("./component.js"); - require("./entity.js"); - require("./node.js"); - require("./node_collection.js"); - require("./system.js"); -} - -/* - * The entity gives the entity framework its name. It exists only - * to hold components. - */ -Class(Serpentity, "Entity")({ - prototype : { - _components : null, - _componentKeys : null, - - init : function init(config) { - var property; - - this._componentKeys = []; - this._components = []; - - for (property in config) { - if (config.hasOwnProperty(property)) { - this[property] = config[property]; - } - } - }, - - /* - * Adds a component to the entity. - * - * returns true if added, false if already present - */ - add : function add(component) { - if (this._componentKeys.indexOf(component.constructor) >= 0) { - return false; - } - this._componentKeys.push(component.constructor); - this._components.push(component); - return true; - }, - - /* - * returns true if component is included, false otherwise - */ - hasComponent : function hasComponent(componentClass) { - if (this._componentKeys.indexOf(componentClass) >= 0) { - return true; - } - return false; - }, - - /* - * returns the component associated with that key - */ - getComponent : function getComponent(componentClass) { - var position; - position = this._componentKeys.indexOf(componentClass); - if (position >= 0) { - return this._components[position]; - } - } - } -}); - -/* - * A node describes a set of components in order to describe entities - * that include them. - */ -Class(Serpentity, "Node")({ - - /* - * Returns true if the given entity matches the defined protocol, - * false otherwise - */ - matches : function matches(entity) { - var property, matched, types; - - types = this.types; - - for (property in this.types) { - - if (this.types.hasOwnProperty(property)) { - matched = false; - - if (entity.hasComponent(types[property])) { - matched = true; - } - - if (!matched) { - return false; - } - } - } - - return true; - }, - - prototype : { - - types : null, - - init : function (config) { - var property; - - this.types = {}; - - for (property in this.constructor) { - if (this.constructor.hasOwnProperty(property)) { - this.types[property] = this.constructor[property]; - } - } - } - } -}); - -/* - * Node Collections contain nodes, in order to keep the lists of nodes - * that belong to each type. - * - * It has a type which is the class name of the node, and an array of - * instances of that class. - */ -Class(Serpentity, "NodeCollection")({ - prototype : { - type : null, - nodes : null, - - init : function init(config) { - var property; - - config = config || {}; - - this.nodes = []; - - for (property in config) { - if (config.hasOwnProperty(property)) { - this[property] = config[property]; - } - } - }, - - /* - * Creates a node for an entity if it matches, and adds it to the - * node list. - * - * Returns true if added, false otherwise. - */ - add : function add(entity) { - var node, types, property; - - if (this.type.matches(entity) && !this._entityExists(entity)) { - node = new this.type({}); - - node.entity = entity; - - types = this.type.types; - - for (property in types) { - if (types.hasOwnProperty(property)) { - node[property] = entity.getComponent(types[property]); - } - } - - this.nodes.push(node); - - return true; - } - - return false; - }, - - /* - * Removes an entity by removing its related node from the list of nodes - * - * returns true if it was removed, false otherwise. - */ - remove : function (entity) { - var found; - found = -1; - this.nodes.forEach(function (node, i) { - if (node.entity === entity) { - found = i; - } - }); - - if (found >= 0) { - this.nodes.splice(found, 1); - return true; - } - - return false; - }, - - /* - * Checks whether we already have nodes for this entity. - */ - _entityExists : function entityExists(entity) { - var found; - found = false; - this.nodes.forEach(function (node) { - if (node.entity === entity) { - found = true; - } - }); - - return found; - } - } -}); - -/* - * Components store data. Nothing to say here really, just - * inherit and add a prototype, or don't even inherit, see? - * It's just an empty class, so what I'm trying to say is your - * components can be any class whatsoever. - */ -Class(Serpentity, "Component")({ - -}); - -/* - * Systems contain most of the logic, and work with nodes in order to - * act and change their values. - * - * You usually want to inherit from this class and override the - * three methods. - */ -Class(Serpentity, "System")({ - prototype : { - - /* - * This will be run when the system is added to the engine - */ - added : function added(engine) { - // Override - }, - - /* - * This will be run when the system is removed from the engine - */ - removed : function removed(engine) { - // Override - }, - - /* - * This will run every time the engine's update method is called - */ - update : function update(dt) { - // Override - } - } -}); +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Serpentity=t():e.Serpentity=t()}(window,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t,n){"use strict";var r,i="object"==typeof Reflect?Reflect:null,s=i&&"function"==typeof i.apply?i.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};r=i&&"function"==typeof i.ownKeys?i.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var o=Number.isNaN||function(e){return e!=e};function u(){u.init.call(this)}e.exports=u,u.EventEmitter=u,u.prototype._events=void 0,u.prototype._eventsCount=0,u.prototype._maxListeners=void 0;var c=10;function f(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function p(e){return void 0===e._maxListeners?u.defaultMaxListeners:e._maxListeners}function l(e,t,n,r){var i,s,o,u;if(f(n),void 0===(s=e._events)?(s=e._events=Object.create(null),e._eventsCount=0):(void 0!==s.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),s=e._events),o=s[t]),void 0===o)o=s[t]=n,++e._eventsCount;else if("function"==typeof o?o=s[t]=r?[n,o]:[o,n]:r?o.unshift(n):o.push(n),(i=p(e))>0&&o.length>i&&!o.warned){o.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=o.length,u=c,console&&console.warn&&console.warn(u)}return e}function h(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function a(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=h.bind(r);return i.listener=n,r.wrapFn=i,i}function d(e,t,n){var r=e._events;if(void 0===r)return[];var i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(e){for(var t=new Array(e.length),n=0;n0&&(o=t[0]),o instanceof Error)throw o;var u=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw u.context=o,u}var c=i[e];if(void 0===c)return!1;if("function"==typeof c)s(c,this,t);else{var f=c.length,p=v(c,f);for(n=0;n=0;s--)if(n[s]===t||n[s].listener===t){o=n[s].listener,i=s;break}if(i<0)return this;0===i?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},u.prototype.listeners=function(e){return d(this,e,!0)},u.prototype.rawListeners=function(e){return d(this,e,!1)},u.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):y.call(e,t)},u.prototype.listenerCount=y,u.prototype.eventNames=function(){return this._eventsCount>0?r(this._events):[]}},function(e,t,n){"use strict";n.r(t),n.d(t,"Component",(function(){return r})),n.d(t,"Entity",(function(){return i})),n.d(t,"Node",(function(){return s})),n.d(t,"System",(function(){return o})),n.d(t,"default",(function(){return f}));class r{constructor(e){Object.assign(this,e)}}class i{constructor(e){this._componentKeys=[],this._components=[],Object.assign(this,e)}addComponent(e){return!(this._componentKeys.indexOf(e.constructor)>=0)&&(this._componentKeys.push(e.constructor),this._components.push(e),!0)}hasComponent(e){return this._componentKeys.indexOf(e)>=0}getComponent(e){const t=this._componentKeys.indexOf(e);if(t>=0)return this._components[t]}}class s{static matches(e){const t=Object.keys(this.types);for(const n of t){const t=this.types[n];let r=!1;if(e.hasComponent(t)&&(r=!0),!r)return!1}return!0}constructor(e){this.types={},Object.assign(this,e)}}class o{added(){}removed(){}update(){}}const u=n(0);class c extends u{constructor(e){super(),this.nodes=[],this.type=null,Object.assign(this,e)}add(e){if(this.type.matches(e)&&!this._entityExists(e)){const t=new this.type({}),n=this.type.types,r=Object.keys(n);t.entity=e;for(const i of r)t[i]=e.getComponent(n[i]);return this.nodes.push(t),this.emit("nodeAdded",{node:t}),!0}return!1}remove(e){let t=-1,n=null;const r=this.nodes.some((r,i)=>{if(r.entity===e)return t=i,n=r,!0});return r&&(this.nodes.splice(t,1),this.emit("nodeRemoved",{node:n})),r}_entityExists(e){let t=!1;for(const n of this.nodes)n.entity===e&&(t=!0);return t}}c.prototype[Symbol.iterator]=function*(){yield*this.nodes};class f{constructor(e){this.systems=[],this.entities=[],this._nodeCollections=[],this._nodeCollectionKeys=[],Object.assign(this,e)}addSystem(e,t){if(this.systems.indexOf(e)>=0)return!1;e.priority=t;let n=0;return this.systems.some((t,r)=>{if(n=r,t.priority>=e.priority)return!0})||(n+=1),this.systems.splice(n,0,e),e.added(this),!0}removeSystem(e){const t=this.systems.indexOf(e);return t>=0&&(this.systems[t].removed(this),this.systems.splice(t,1),!0)}addEntity(e){if(this.entities.indexOf(e)>=0)return!1;this.entities.push(e);for(const t of this._nodeCollections)t.add(e);return!0}removeEntity(e){const t=this.entities.indexOf(e);if(t>=0){for(const t of this._nodeCollections)t.remove(e);return this.entities.splice(t,1),!0}return!1}getNodes(e){const t=this._nodeCollectionKeys.indexOf(e);if(t>=0)return this._nodeCollections[t].nodes;const n=new c({type:e});this._nodeCollectionKeys.push(e),this._nodeCollections.push(n);for(const e of this.entities)n.add(e);return n}update(e){for(const t of this.systems)t.update(e)}}}])}));