X-Git-Url: https://git.r.bdr.sh/rbdr/serpentity/blobdiff_plain/1bd778d281811ad568cf976330da1c550119d5ad..efee4ba168340dbb22e65f0f63f04e609cc07117:/dist/serpentity.js?ds=sidebyside diff --git a/dist/serpentity.js b/dist/serpentity.js index 8871985..e57efd5 100644 --- a/dist/serpentity.js +++ b/dist/serpentity.js @@ -1,521 +1 @@ -'use strict'; - -/* -Serpentity is a simple entity framework inspired by Ash. - -Usage: - - let Serpentity = require('serpentity'); - -## Instantiating an engine - - let 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. - - let 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" - - let PositionComponent = class PositionComponent extends Serpentity.Component { - constructor (config) { - this.x = 0; - this.y = 0; - - super(config); - } - }; - -You can add components to entities by using the add method: - - entity.addComponent(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. - - let MovementNode = class MovementNode extends Serpentity.Node; - MovementNode.position = PositionComponent; - MovementNode.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. - - let TestSystem = class TestSystem extends Serpentity.System { - added (engine){ - this.nodeList = engine.getNodes(MovementNode); - }, - removed (engine){ - this.nodeList = undefined; - } - update (dt){ - let node; - for (node of this.nodeList) { - console.log(`Current position is: ${node.position.x},${node.position.y}`); - } - } - }; - -## That's it - -Just run `engine.update(dt)` in your game loop :D - -*/ -let Serpentity = class Serpentity { - - constructor (config) { - this.systems = []; - this.entities = []; - this._nodeCollections = []; - this._nodeCollectionKeys = []; - - Object.assign(this, config || {}); - } - - /* - * 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 (system, priority) { - let 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 (system) { - let 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 (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 (entity) { - let 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 (nodeType) { - let 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 (dt) { - this.systems.forEach(function (system) { - system.update(dt); - }); - } -}; - -// Add namespaced objects. -if (typeof module !== 'undefined' && this.module !== module) { - Serpentity.Component = require('./serpentity/component.js'); - Serpentity.Entity = require('./serpentity/entity.js'); - Serpentity.Node = require('./serpentity/node.js'); - Serpentity.NodeCollection = require('./serpentity/node_collection.js'); - Serpentity.System = require('./serpentity/system.js'); - - module.exports = Serpentity; -} else { - window.Serpentity = Serpentity; -} - -'use strict'; - -/* global Serpentity */ - -/* - * The entity gives the entity framework its name. It exists only - * to hold components. - */ - -let Entity = class Entity { - constructor (config) { - this._componentKeys = []; - this._components = []; - - Object.assign(this, config || {}); - } - - /* - * Adds a component to the entity. - * - * returns true if added, false if already present - */ - addComponent (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 (componentClass) { - if (this._componentKeys.indexOf(componentClass) >= 0) { - return true; - } - return false; - } - - /* - * returns the component associated with that key - */ - getComponent (componentClass) { - let position; - position = this._componentKeys.indexOf(componentClass); - if (position >= 0) { - return this._components[position]; - } - } -}; - -if (typeof module !== 'undefined' && this.module !== module) { - module.exports = Entity; -} else { - Serpentity.Entity = Entity; -} - -'use strict'; - -/* global Serpentity */ - -/* - * A node describes a set of components in order to describe entities - * that include them. - */ -let Node = class Node { - - /* - * Returns true if the given entity matches the defined protocol, - * false otherwise - */ - static matches (entity) { - let property, types; - - types = this.types; - - for (property in types) { - if (types.hasOwnProperty(property)) { - let matched, type; - - matched = false; - type = types[property]; - if (entity.hasComponent(type)) { - matched = true; - } - if (!matched) { - return false; - } - } - } - - return true; - } - - constructor (config) { - this.types = {}; - - Object.assign(this, config || {}); - } -}; - -if (typeof module !== 'undefined' && this.module !== module) { - module.exports = Node; -} else { - Serpentity.Node = Node; -} - -'use strict'; - -/* global Serpentity */ - -/* - * 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. - */ - -let NodeCollection = class NodeCollection { - - constructor (config) { - this.nodes = []; - this.type = null; - - Object.assign(this, config || {}); - } - - /* - * Creates a node for an entity if it matches, and adds it to the - * node list. - * - * Returns true if added, false otherwise. - */ - add (entity) { - - if (this.type.matches(entity) && !this._entityExists(entity)) { - let node, types, property; - - 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 (entity) { - let 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 (entity) { - let found, node; - - found = false; - for (node of this.nodes) { - if (node.entity === entity) { - found = true; - } - } - - return found; - } -}; - -if (typeof module !== 'undefined' && this.module !== module) { - module.exports = NodeCollection; -} else { - Serpentity.NodeCollection = NodeCollection; -} - -'use strict'; - -/* global Serpentity */ - -/* - * 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. - */ - -let Component = class Component { - constructor (config) { - Object.assign(this, config || {}); - } -}; - -if (typeof module !== 'undefined' && this.module !== module) { - module.exports = Component; -} else { - Serpentity.Component = Component; -} - -'use strict'; - -/* global Serpentity */ - -/* - * 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. They are shown here to document the interface. - */ - -let System = class System { - - /* - * This will be run when the system is added to the engine - */ - added () { - // Override with added(engine) - // Receives an instance of the serpentity engine - } - - /* - * This will be run when the system is removed from the engine - */ - removed () { - // Override with removed(engine) - // Receives an instance of the serpentity engine - } - - /* - * This will run every time the engine's update method is called - */ - update () { - // Override with update(dt) - // Receives a delta of the time - } -}; - -if (typeof module !== 'undefined' && this.module !== module) { - module.exports = System; -} else { - Serpentity.System = System; -} +!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)}}}])}));