sam-ecs
Version:
A specialized entity component system
357 lines (302 loc) • 11.1 kB
JavaScript
'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;