@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
204 lines (145 loc) • 6.01 kB
JavaScript
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;
}