/**
* This is a container to hold components,tags and event handlers.
*
* @class
* @public
*/
export class Entity {
/**
* Dictionary of component to manage.
*
* @private
* @type Object<string,Component>
*/
_components = {}
/**
* Dictionary of handlers to call during an event.
*
* @private
* @type Object<string,function>
*/
_handlers = {}
/**
* A list of tags to identify an entity.
*
* @private
* @type Set<string>
*/
_tags = new Set()
/**
* The manager handling this entity.
*
* @private
* @type Manager
*/
_global = null
/**
* A flag to show if the entity is added to a manager.
*
* @type {boolean}
*/
active = false
/**
* @type {string}
*/
get CHAOS_OBJ_TYPE() {
return "entity"
}
/**
* @type {string}
*/
get CHAOS_CLASSNAME() {
return this.constructor.name.toLowerCase()
}
/**
* Removes all components and handlers from an entity while removing it from its manager
*/
destroy() {
for (let k in this._components) {
let comp = this._components[k]
if (comp.destroy)
comp.destroy()
delete this._components[k]
}
for (let k in this._handlers) {
delete this._handlers[k]
}
this.removeSelf()
}
/**
* Removes an entity and its components from its manager whilst retaining its components and handlers
*/
removeSelf() {
if (this._global) this._global.remove(this)
}
/**
* This is an internal function,no need to use it.
*
* @package
*/
reset() {
this.active = false
this._global = null
}
/**
* Removes all components of an entity from its manager but keeps the entity inside the manager.
* This is an internal function so no need on your part to use it.
*/
removeComponents() {
if (this._global === void 0) return
for (var k in this._components) {
this._global.removeComponent(k, this._components[k])
}
}
/**
* Gets the current manager of an entity
*
* @returns {Manager}
*/
get manager() {
return this._global
}
/**
* Adds a component into an entity
*
* @param {String} n Name of the component.
* @param {Component} c The component to add.
*
* @returns {this}
*/
attach(n, c) {
this._components[n] = c
if (this.manager) {
c.init(this)
this._global.addComponent(n, c)
}
return this
}
/**
* Removes a component from an entity.
*
* @param {String} n Name pf the component
* @rerurns {this}
*/
remove(n) {
this._global.removeComponent(n, this._components[n])
delete this._components[n]
return this
}
/**
* Registers a function to handle a named event.
*
* @param {string} n Name of the event
* @param {function} h The function to be called when an event is fired.
*/
register(n, h) {
this._handlers[n] = h
}
/**
* Removes an event handler function of the given name
*
* @param {string} n Name of the event
*/
unregister(n) {
if (!(n in this._handlers)) return
delete this._handlers[n]
}
/**
* Returns an event handler which can be fired during an event
*
* @param {string} n Name of the event
* @returns {function | undefined}
*/
getHandler(n) {
return this._handlers[n]
}
/**
* Returns the named component.
*
* @param {string} n Name of the component.
* @returns {Component | undefined }
*/
get(n) {
return this._components[n]
}
/**
* Used to check if the component exists in an entity
*
* @param {string} n Name of the component.
* @returns {boolean}
*/
has(n) {
return n in this._components
}
/**
* Adds a tag into an entity.
*
* @param {string} n The tag to be added
*/
addTag(n) {
this._tags.add(n)
}
/**
* Removes a tag from an entity.
*
* @param {string} n The tag to be added
*/
removeTag(n) {
this._tags.delete(n)
}
/**
* Checks if a tag exists in an entity.
*
* @param {string} n The tag to be added
* @returns {boolean}
*/
hasTag(n) {
return this._tags.has(n)
}
/**
* Initializes the components within an entity and marks it as active.
* It is called by an instance of a game manager so no need to call it manually
*
* @package
* @param {Manager} global
*/
init(global) {
this._global = global
this.active = true
for (let k in this._components) {
this._components[k].init(this)
global.addComponent(k, this._components[k])
}
}
/**
* A helper function to create a new Entity with transform,movable and bounds components.
*
* @depreciated
* @param {number} x
* @param {number} y
* @param {number} a
* @returns {Entity}
*/
static Default(x, y, a) {
console.warn("'Entity.Default()' is depreciated,use 'createEntity()' instead.")
return new Entity()
.attach("transform", new Transform(x, y, a))
.attach("movable", new Movable())
.attach("bounds", new Bound())
}
/**
* Search an entity's manager for entities in a given bound.
*
* @param {Bounds} bound the region to search entitities in.
* @param {Entity[]} [target=[]] An array to store results in.
* @returns {Entity[]}
*/
query(bound, target = []) {
return this._global.query(bound, target)
}
/**
* Todo - type serialization docs correctly
* @param {{}} obj
* @param {Map<string,function>} compList
*/
fromJSON(obj, compList) {
let entity = this
obj.tags.forEach((a) => {
entity.addTag(a)
})
for (var key in obj.comps) {
let c = new compList[key]().fromJSON(obj.comps[key])
entity.attach(key, c)
}
return entity
}
toJson() {
let obj = {
comps: {},
tags: []
}
for (var key in this._components) {
obj.comps[key] = this._components[key].toJson()
}
this._tags.forEach((a) => {
obj.tags.push(a)
})
obj.type = this.CHAOS_OBJ_TYPE
return obj
}
}