UNPKG

sam-ecs

Version:

A specialized entity component system

357 lines (302 loc) 11.1 kB
'use strict'; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } //Entity.js// /** * @description - Defines an entity-- which is essentially a bag of components * @author - Samuel Faulkner */ //node imports var Dict = require('collections/dict.js'); var isEqual = require('lodash/isEqual.js'); //user imports var StringGenerator = require('./utils/RandomStringGenerator.js'); //constants var HASH_LENGTH = 8; var Entity = function () { function Entity(manager) { _classCallCheck(this, Entity); this._manager = manager || null; this._components = new Dict(); } _createClass(Entity, [{ key: 'clearManager', value: function clearManager() { this._manager = null; } }, { key: 'setManager', value: function setManager(manager) { this._manager = manager; } }, { key: 'hash', value: function hash() { if (this._hash === undefined) { this._hash = StringGenerator(8); } return this._hash; } /** * @description - Resets the hash value associated with this entity * @param {String} value - the new hash value */ }, { key: '_setHash', value: function _setHash(value) { this._hash = value; //reset the hash value in each component var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this._components.keys()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var componentName = _step.value; this._components.get(componentName).set(entity, value); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } /** * @description - Adds a component object to this entity * @param {Object} component - object denoting the component to be added. * must have at least two fields: 'name' and 'state'. the 'state' field also * must be an object */ }, { key: 'addComponent', value: function addComponent(component) { var notifyManager = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (!(component.name !== undefined && component.state !== undefined && _typeof(component.state) === 'object')) { throw "Component must have 'name' and 'state'!"; } // this should create a copy of the state this._components.set(component.name, new Dict({ 'state': Object.assign({}, component.state), 'init': component.init, 'remove': component.remove })); if (this._manager) { this._manager._addEntityToComponentList(this.hash(), component.name); if (notifyManager) this._manager._invalidateProcessorListsByEntityComponent(this.hash(), component.name); } // var componentDict = this._components.get(component.name), // initFunction = componentDict.get('init'); // if (initFunction) { // initFunction(componentDict.get('state'), componentDict); // } } /** * @description - Returns the object contianing all of the objects for this * entity * @return {Object} - contains all the entities components */ }, { key: 'getComponents', value: function getComponents() { return this._components; } /** * @description - Returns the given component's state * @param {String} name - the name of the component * @return {Object} the state of the component referred to by the given * name */ }, { key: 'getComponent', value: function getComponent(name) { if (!this._components.has(name)) { throw "'" + name + "' isn't a component of this entity!"; } return this._components.get(name); } /** * @description - Deletes a component from the entity * @param {String} name - the name of the component to be deleted */ }, { key: 'removeComponent', value: function removeComponent(name) { var notifyManager = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (!this._components.has(name)) { throw new TypeError("'" + name + "' isn't a component of this entity!"); } this.removeComponentMethod(name); this._components.delete(name); if (this._manager) { if (this._manager.hasComponent(name) && this._manager.getEntitiesByComponent(name).has(this.hash())) this._manager._removeEntityFromComponentList(this.hash(), name); if (notifyManager) { this._manager._invalidateProcessorListsByEntityComponent(this.hash(), name); } } } /** * @description - Calls the init function on all our components */ }, { key: 'initializeComponents', value: function initializeComponents() { this._components.forEach(function (value, key, dict) { var initFunction = value.get('init'); if (initFunction) { initFunction(value.get('state'), value); } }); } }, { key: 'removeComponentsMethod', value: function removeComponentsMethod() { this._components.forEach(function (value, key, dict) { var removeFunction = value.get('remove'); if (removeFunction) removeFunction(value); }); } }, { key: 'removeComponentMethod', value: function removeComponentMethod(componentName) { var componentObject = this._components.get(componentName); if (componentObject) { var removeFunction = componentObject.get('remove'); if (removeFunction) removeFunction(componentObject); } } /** * @description - Calls remove component on every component */ }, { key: 'removeComponents', value: function removeComponents(notifyManager) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this._components.keys()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var key = _step2.value; this.removeComponent(key, notifyManager); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } }, { key: 'serialize', value: function serialize() { var components = {}; this._components.forEach(function (value, key, dict) { components[key] = Object.assign({}, value.get('state')); }); return { 'components': components, 'hash': this.hash() }; } /** * @description - Takes the given object and implements the state * given * @param {Object} entityState - the object that represents the state * of the entity. Most likely generated from {@link serialize} */ }, { key: 'deserialize', value: function deserialize(entityState, componentManager) { var _this = this; var states = {}; this._components.forEach(function (value, key, dict) { states[key] = value.get('state'); _this.removeComponent(key, false); }); this._hash = entityState.hash; for (var componentName in entityState.components) { this.addComponent(componentManager.createComponent(componentName, Object.assign({}, states[componentName], entityState.components[componentName])), false); } } /** * @description - Equality check for entities * @param {Entity} entity - the entity to check equality against * @returns {Boolean} is this equivalent to the other entity */ }, { key: 'equals', value: function equals(entity) { var otherComponents = entity.getComponents(); if (this._components.length != otherComponents.length) { return false; } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = this._components.keys()[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var componentName = _step3.value; if (!otherComponents.has(componentName)) { return false; } var otherComponent = otherComponents.get(componentName); if (!isEqual(this._components.get(componentName).get('state'), otherComponent.get('state'))) { return false; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } return true; } /** * @description - Clones this entity * @returns {Entity} the cloned entity */ }, { key: 'clone', value: function clone() { var returnEntity = new Entity(); returnEntity._setHash(this.hash()); this._components.forEach(function (value, key, dict) { var componentObject = { 'name': key, 'state': Object.assign({}, value.get('state')), 'init': value.get('init'), 'remove': value.get('remove') }; returnEntity.addComponent(componentObject); }); return returnEntity; } }]); return Entity; }(); module.exports = Entity;