UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

204 lines (145 loc) • 6.01 kB
import { TransitionPropertyVectorXBehavior } from "../../../../../model/game/story/behaviors/generic/TransitionPropertyVectorXBehavior.js"; import { TweenVector1Behavior } from "../../../../../model/game/util/behavior/TweenVector1Behavior.js"; import { TweenVector3Behavior } from "../../../../../model/game/util/behavior/TweenVector3Behavior.js"; import { max2 } from "../../../core/math/max2.js"; import { min2 } from "../../../core/math/min2.js"; import { Light } from "../../graphics/ecs/light/Light.js"; import Mesh, { MeshFlags } from "../../graphics/ecs/mesh/Mesh.js"; import Trail2D from "../../graphics/ecs/trail2d/Trail2D.js"; import { Trail2DFlags } from "../../graphics/ecs/trail2d/Trail2DFlags.js"; import { ParticleEmitter } from "../../graphics/particles/particular/engine/emitter/ParticleEmitter.js"; import { ParticleEmitterFlag } from "../../graphics/particles/particular/engine/emitter/ParticleEmitterFlag.js"; import { SequenceBehavior } from "../../intelligence/behavior/composite/SequenceBehavior.js"; import { BehaviorComponent } from "../../intelligence/behavior/ecs/BehaviorComponent.js"; import { DieBehavior } from "../../intelligence/behavior/ecs/DieBehavior.js"; import { DelayBehavior } from "../../intelligence/behavior/util/DelayBehavior.js"; import { SoundEmitter } from "../../sound/ecs/emitter/SoundEmitter.js"; import { Transform } from "../transform/Transform.js"; /** * @readonly * @type {number} */ const SHUTDOWN_GRACE_PERIOD = 60; /** * * @type {Map<Class|function, function(T,entity?:Entity,createEntity?:function,createEntityContext?:*):number>} */ const component_shutdown = new Map(); /** * @template T * @param {Class<T>} type * @param {function(T,entity?:Entity,createEntity?:function,createEntityContext?:*):number} method */ function addShutdown(type, method) { component_shutdown.set(type, method); } addShutdown(ParticleEmitter, emitter => { //stop emission emitter.clearFlag(ParticleEmitterFlag.Emitting); //figure out how long the emitter should stay alive const maxLife = emitter.computeMaxEmittingParticleLife(SHUTDOWN_GRACE_PERIOD); return maxLife; }); addShutdown(Trail2D, trail => { trail.clearFlag(Trail2DFlags.Spawning); return trail.maxAge; }); addShutdown(Mesh, (mesh, builder, createEntity, createEntityThisArg) => { /** * * @type {Transform} */ const transform = builder.getComponent(Transform); let delay = 0; if (mesh !== null && transform !== null) { if (mesh.getFlag(MeshFlags.Loaded | MeshFlags.InView) && !transform.scale.isZero()) { const scale = new TweenVector3Behavior(); scale.startValue.copy(transform.scale); scale.targetValue.set(0, 0, 0); scale.target = transform.scale; scale.duration = 0.2; delay = max2(scale.duration, delay); const eb = createEntity.call(createEntityThisArg); eb.add(BehaviorComponent.from(SequenceBehavior.from([ scale, DieBehavior.create() ]))); } else { transform.scale.set(0, 0, 0); } } return delay; }); addShutdown(Light, (light, builder, createEntity, createEntityThisArg) => { let delay = 0.2; const eb = createEntity.call(createEntityThisArg); eb.add(BehaviorComponent.from(SequenceBehavior.from([ TransitionPropertyVectorXBehavior.from({ component: 'Light', path: 'intensity', target: [0], duration: delay, entity: builder.id }), DieBehavior.create() ]))); return delay; }); addShutdown(SoundEmitter, (soundEmitter, builder, createEntity, createEntityThisArg) => { let delay = 0; if (soundEmitter.volume.getValue() > 0) { const tracks = soundEmitter.tracks.asArray(); const n = tracks.length; for (let i = 0; i < n; i++) { const soundTrack = tracks[i]; if (soundTrack.volume > 0) { const setVolume = new TweenVector1Behavior(); setVolume.startValue = soundEmitter.volume.getValue(); setVolume.targetValue = 0; setVolume.target = soundEmitter.volume; setVolume.duration = 2.7; delay = SHUTDOWN_GRACE_PERIOD; const eb = createEntity.call(createEntityThisArg); eb.add(BehaviorComponent.from(SequenceBehavior.from([ DelayBehavior.from(SHUTDOWN_GRACE_PERIOD - setVolume.duration), setVolume, DieBehavior.create() ]))); break; } } } return delay; }); /** * * @param {Entity} builder * @param {function():Entity} createEntity * @param {*} [createEntityThisArg] * @return {number} duration in seconds until the entity is completely hidden */ export function hideEntityGracefully(builder, createEntity, createEntityThisArg) { if (!builder.isBuilt) { // already destroyed return 0; } let delay = 0; const components = builder.components; const component_count = components.length; for (let i = 0; i < component_count; i++) { const component = components[i]; const shutdown_method = component_shutdown.get(Object.getPrototypeOf(component).constructor); if (shutdown_method === undefined) { continue; } const sd = shutdown_method(component, builder, createEntity, createEntityThisArg); if (Number.isNaN(sd) || !Number.isFinite(sd)) { continue; } delay = max2(sd, delay); } delay = min2(delay, SHUTDOWN_GRACE_PERIOD); return delay; }