src/object/GameObject.js
import Updateable from '../base/Updateable';
import Component from '../component/Component';
import Transform from '../component/Transform';
/**
* Baseclass GameObject which derives from Updateable.
*
* Do not derive this class directly! GameObjects are not managed until they are assigned to a manager.
* Instead, derive SceneObject or PersistentObject to create objects that exist the scope of a scene, or the scope of the game.
*
* All objects that should exist in the game screen should derive this.
*/
export default class GameObject extends Updateable {
/**
* Default position, size and rotation of the Object.
*
* @param {Point} position A point of creation in the world.
* @param {Point} size A point representing scale of the object.
* @param {number} rotation A number representing angular rotation (in degrees).
*/
constructor(position = new Point(0, 0, 0), size = new Point(32, 32, 1), rotation = 0) {
super();
this.className = 'GameObject';
this.components = {};
this.addComponent(new Transform(position, size, rotation));
this.transform = this.getComponent("Transform");
}
/**
* Adds a component to this game object, and keeps reference to it.
* GameObjects will handle their components as they are added to the object.
*
* @param {Component} component The component assigned to this object.
*/
addComponent(component) {
if (this.components[component.className] == null) {
this.components[component.className] = [];
}
if (component.isUnique && this.components[component.className].length > 0) {
throw 'There is already a unique component of type ' + component.className + ' on this GameObject!';
return false;
}
this.components[component.className].push(component);
component.gameObject = this;
component.onAddComponent();
return true;
}
/**
* Removes a single component from this GameObject by ID.
*
* @param {number} componentID Id of the component to remove.
*/
removeComponent(componentName, componentID) {
if (this.components[componentName] == null)
return false;
for (let i = 0; i < this.components[componentName].length; i++) {
if (this.components[componentName][i].id === componentID) {
let comp = this.components[componentName][i];
this.components[componentName].splice(i, 1);
comp.end();
return true;
}
}
return false;
}
/**
* Removes all Components of the named type.
*
* @param {string} componentName The name of the components to clear.
*/
removeComponents(componentName) {
if (this.components[componentName] == null)
return false;
for (let i = this.components[componentName].length - 1; i >= 0; i--) {
let comp = this.components[componentName][i];
this.components[componentName].splice(i, 1);
comp.end();
}
return true;
}
/**
* Removes all components except for the Transform component.
*/
removeAllComponents() {
let compTypes = Object.keys(this.components);
for (let i = 0; i < compTypes.length; i++) {
let thisCompType = compTypes[i];
if (thisCompType === 'Transform')
continue;
for (let ii = 0; ii < this.components[thisCompType].length; ii++) {
this.components[thisCompType][ii].end();
}
this.components[thisCompType] = [];
}
return true;
}
/**
* Returns a boolean on if there is a component of type {componentName}.
*
* @param {string} componentName Name of the component type to search for.
*
* @returns {boolean} true if there is at least one component of this type.
*/
hasComponent(componentName) {
if (this.components[componentName] == null) {
return false;
}
return this.components[componentName].length > 0;
}
/**
* Returns a component of type {componentName}. The second parameter can determine which
* Component of that type to return if there are more than 1.
*
* @param {string} componentName Name of the component type to return.
* @param {*} index Index of the component to get. Defaults to first component.
*/
getComponent(componentName, index = 0) {
if (this.components[componentName] == null) {
return null;
}
return this.components[componentName][index];
}
/**
* Updates all components on this GameObject.
*/
updateComponents() {
let compTypes = Object.keys(this.components);
for (let i = 0; i < compTypes.length; i++) {
let thisCompType = compTypes[i];
for (let ii = 0; ii < this.components[thisCompType].length; ii++) {
this.components[thisCompType][ii].update();
}
}
}
onPause() {
let compTypes = Object.keys(this.components);
for (let i = 0; i < compTypes.length; i++) {
let thisCompType = compTypes[i];
for (let ii = 0; ii < this.components[thisCompType].length; ii++) {
this.components[thisCompType][ii].pause();
}
}
}
onUnpause() {
let compTypes = Object.keys(this.components);
for (let i = 0; i < compTypes.length; i++) {
let thisCompType = compTypes[i];
for (let ii = 0; ii < this.components[thisCompType].length; ii++) {
this.components[thisCompType][ii].unpause();
}
}
}
/**
* Rewritten update() functions which is originally defined in Updateable.
* The GameObject adds a pre and post update function, and respective overrideable callbacks
* (onPreUpdate and onPostUpdate).
*/
update() {
if (this.hasPaused)
return;
if (!this.hasStarted) {
this.start();
return;
}
this.preUpdate();
this.onUpdate();
this.updateComponents();
this.postUpdate();
}
/**
* Called by the GameObject before an update to do default calls for preUpdating. Afterwards it
* calls the overrideable function, onPreUpdate.
*/
preUpdate() {
this.onPreUpdate();
}
/**
* Called by the GameObject after an update to do default calls for postUpdating. Afterwards it
* calls the overrideable function, onPostUpdate.
*/
postUpdate() {
this.onPostUpdate();
}
/**
* Override for Pre Update functionality.
*/
onPreUpdate() {}
/**
* Override for Post Update functionality.
*/
onPostUpdate() {}
}