UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

205 lines (204 loc) 7.36 kB
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); } }