the-world-engine
Version:
three.js based, unity like game engine for browser
205 lines (204 loc) • 7.36 kB
JavaScript
import { Coroutine } from "../coroutine/Coroutine";
import { ComponentEventContainer } from "./ComponentEventContainer";
/**
* component is the base class from which every engine script derives
*
* do not override constructor it's break the engine
*/
export class Component {
/**
* if this true, this component can't be added multiple times to the same game object
*/
disallowMultipleComponent = false;
/**
* if this array is not empty, this component can be added only if all of the components in this array are already added to the game object
*/
requiredComponents = [];
/**
* script execution order of this component
*/
executionOrder = 0;
_private__enabled;
_private__gameObject;
_private__instanceId;
_private__runningCoroutines = [];
/** @internal */
// eslint-disable-next-line @typescript-eslint/naming-convention
_engine_internal_componentEventContainer;
/** @internal */
// eslint-disable-next-line @typescript-eslint/naming-convention
_engine_internal_destroyed = false;
constructor(gameObject) {
this._private__enabled = true;
this._private__gameObject = gameObject;
this._private__instanceId = gameObject.engine.instantiater.generateId();
this._engine_internal_componentEventContainer = null;
}
/** @internal */
// eslint-disable-next-line @typescript-eslint/naming-convention
engine_internal_constructAfterProcess() {
this._engine_internal_componentEventContainer = new ComponentEventContainer(this);
Object.defineProperties(this, {
disallowMultipleComponent: {
configurable: false,
writable: false
},
requiredComponents: {
configurable: false,
writable: false
},
executionOrder: {
configurable: false,
writable: false
}
});
}
/**
* starts a coroutine
*
* if component is destroyed this will throw an error
* @param coroutineIterator coroutine iterator
* @returns coroutine instance. you can stop coroutine by calling stopCoroutine(coroutine: ICoroutine) with this variable
*/
startCoroutine(coroutineIterator) {
this._private_checkComponentIsExist();
const coroutine = new Coroutine(this, coroutineIterator, () => {
const index = this._private__runningCoroutines.indexOf(coroutine);
if (index >= 0) {
this._private__runningCoroutines.splice(index, 1);
}
});
coroutine.fatchNextInstruction();
if (!this._private__gameObject.activeInHierarchy)
return coroutine;
this._private__runningCoroutines.push(coroutine);
this.engine.coroutineProcessor.addCoroutine(coroutine);
return coroutine;
}
/**
* stop all coroutines executed by this component
*
* if component is destroyed this will throw an error
*/
stopAllCoroutines() {
this._private_checkComponentIsExist();
const runningCoroutines = this._private__runningCoroutines;
const coroutineProcessor = this.engine.coroutineProcessor;
for (let i = 0; i < runningCoroutines.length; ++i) {
const coroutine = runningCoroutines[i];
if (coroutine.component !== this) {
throw new Error("Coroutine is not owned by this component");
}
coroutineProcessor.removeCoroutine(coroutine);
}
runningCoroutines.length = 0;
}
/**
* stop coroutine that is executed by this component
*
* if component is destroyed this will throw an error
* @param coroutine coroutine instance
*/
stopCoroutine(coroutine) {
this._private_checkComponentIsExist();
if (coroutine.component !== this) {
throw new Error("Coroutine is not owned by this component");
}
this.engine.coroutineProcessor.removeCoroutine(coroutine);
const index = this._private__runningCoroutines.indexOf(coroutine);
if (index >= 0) {
this._private__runningCoroutines.splice(index, 1);
}
}
/**
* enabled components are updated, disabled components are not
*/
get enabled() {
return this._private__enabled;
}
/**
* enabled components are updated, disabled components are not
*
* if component is destroyed this will throw an error
*/
set enabled(value) {
this._private_checkComponentIsExist();
if (this._private__enabled === value)
return;
this._private__enabled = value;
if (!this._private__gameObject.initialized)
return;
if (this._private__gameObject.activeInHierarchy) {
if (this._private__enabled) {
this._engine_internal_componentEventContainer.tryRegisterOnEnable();
this._engine_internal_componentEventContainer.tryRegisterStart();
this._engine_internal_componentEventContainer.tryRegisterUpdate();
this.engine.sceneProcessor.tryStartProcessSyncedEvent();
}
else {
this._engine_internal_componentEventContainer.tryRegisterOnDisable();
this._engine_internal_componentEventContainer.tryUnregisterStart();
this._engine_internal_componentEventContainer.tryUnregisterUpdate();
this.engine.sceneProcessor.tryStartProcessSyncedEvent();
}
}
}
_private_checkComponentIsExist() {
if (this._engine_internal_destroyed) {
throw new Error("Component " + this.constructor.name + " is destroyed");
}
}
/**
* game object this component belongs to
*/
get gameObject() {
return this._private__gameObject;
}
/**
* transform attached to this component game object
*/
get transform() {
return this._private__gameObject.transform;
}
/**
* global engine object
*/
get engine() {
return this._private__gameObject.engine;
}
/**
* get instance id of this component
*/
get instanceId() {
return this._private__instanceId;
}
/**
* if instantiate process is finished, this will be true
*/
get initialized() {
return this._private__gameObject.initialized;
}
/**
* does the component exist?
*/
get exists() {
return !this._engine_internal_destroyed;
}
/**
* destroy this component
*/
destroy() {
if (this._engine_internal_destroyed)
return;
if (this.enabled && this.gameObject.activeInHierarchy) {
this._engine_internal_componentEventContainer.tryRegisterOnDisable();
this._engine_internal_componentEventContainer.tryUnregisterStart();
this._engine_internal_componentEventContainer.tryUnregisterUpdate();
}
this.stopAllCoroutines();
this._engine_internal_componentEventContainer.tryRegisterOnDestroy();
this._engine_internal_destroyed = true;
this.engine.sceneProcessor.tryStartProcessSyncedEvent();
this.engine.sceneProcessor.addRemoveComponent(this);
}
}