entity.js

/**
 * The entity module exports the Entity class
 *
 * @module entity
 */

import _ from 'lodash';
import EventEmitter from 'events';

/**
 * The entity class expose methods to associate
 * the entity to components and to get/set components data.<br/>
 * To create a new entity, use the Engine.entity() method.
 *
 * @extends EventEmitter
 */
class Entity extends EventEmitter {
  /**
    * Do not instantiate this class directly, use the Engine.entity() method.
    *
    * @private
    * @param {String} name Entity name
    */
  constructor(name) {
    super();
    if (typeof name !== 'string') throw new Error('name must be a string');

    this.name = name;
    this.components = {};
  }

  /**
   * Returns this entity name
   *
   * @return {String} this entity name
   */
  getName() {
    return _.clone(this.name);
  }

  /**
   * Check if the entity is associated to a component
   *
   * @param {String} componentName Name of the component
   * @return {Boolean} true if the entity has the component associated, false otherwise.
   */
  hasComponent(componentName) {
    if (typeof componentName !== 'string') throw new Error('componentName must be a string');
    return this.components[componentName] !== undefined;
  }

  /**
   * Associate the entity to a component.
   * The component can be any type.
   *
   * @param {String} componentName The component name
   * @param {*} componentData The component data
   */
  setComponent(componentName, componentData) {
    if (typeof componentName !== 'string') throw new Error('componentName must be a string');

    // If this is a new association update system vs entity associations
    let newComponent = false;
    if (this.components[componentName] === undefined) {
      newComponent = true;
    }

    // Set component data
    this.components[componentName] = componentData;
    if (newComponent) {
      this.emit('component:add', newComponent);
    }
  }

  /**
   * Retrieve a component by name
   *
   * @param {String} componentName The component name
   */
  getComponent(componentName) {
    if (typeof componentName !== 'string') throw new Error('componentName must be a string');

    return this.components[componentName];
  }

  /**
   * Remove a component association
   *
   * @param {String} componentName
   */
  deleteComponent(componentName) {
    if (typeof componentName !== 'string') throw new Error('componentName must be a string');

    if (this.hasComponent(componentName)) {
      delete this.components[componentName];

      // update system vs entity associations
      this.emit('component:remove', componentName);
    }
  }

  /**
   * Remove this entity from the engine
   */
  destroy() {
    this.emit('entity:remove', this.name);
  }
}

export default Entity;