UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

274 lines (216 loc) • 6.21 kB
import { BvhClient } from "../../../../core/bvh2/bvh3/BvhClient.js"; import Vector3 from "../../../../core/geom/Vector3.js"; import Vector4 from "../../../../core/geom/Vector4.js"; import { clamp01 } from "../../../../core/math/clamp01.js"; import ThreeFactory from "../../three/ThreeFactory.js"; import { RIBBON_ATTRIBUTE_ADDRESS_AGE } from "../../trail/x/ribbon_attributes_spec.js"; import { RibbonX } from "../../trail/x/RibbonX.js"; import { RibbonXMaterialSpec } from "../../trail/x/RibbonXMaterialSpec.js"; import { makeGradientTrail } from "./makeGradientTrail.js"; import { Trail2DFlags } from "./Trail2DFlags.js"; const DEFAULT_FLAGS = Trail2DFlags.Spawning | Trail2DFlags.Aging | Trail2DFlags.BoundsNeedUpdate; const DEFAULT_MAX_AGE = 5; const DEFAULT_WIDTH = 1; const v3_array = new Float32Array(3); class Trail2D { /** * Age at which trail segment disappears, in seconds * @type {number} */ maxAge = DEFAULT_MAX_AGE; /** * Trail width * @type {number} */ width = DEFAULT_WIDTH; /** * Current simulated time since trail birth * @type {number} */ time = 0; /** * * @type {number} */ trailingIndex = 0; /** * Time elapsed since last update * @type {number} */ timeSinceLastUpdate = 0; /** * @readonly * @type {Vector4} */ color = new Vector4(1, 1, 1, 1); /** * World offset * @readonly * @type {Vector3} */ offset = new Vector3(); /** * transient * @type {RibbonX|null} */ ribbon = null; /** * transient * @type {RibbonXMaterialSpec} */ material = new RibbonXMaterialSpec(); /** * @readonly * @type {BvhClient} */ bvh = new BvhClient(); /** * @private * @type {Trail2DFlags|number} */ flags = DEFAULT_FLAGS; dispose() { if (this.ribbon === null) { // nothing to dispose return; } this.ribbon.dispose(); this.ribbon = null; } get textureURL() { return this.material.diffuse; } set textureURL(v) { this.material.diffuse = v; } /** * * @param {number|Trail2DFlags} flag * @returns {void} */ setFlag(flag) { this.flags |= flag; } /** * * @param {number|Trail2DFlags} flag * @returns {void} */ clearFlag(flag) { this.flags &= ~flag; } /** * * @param {number|Trail2DFlags} flag * @param {boolean} value */ writeFlag(flag, value) { if (value) { this.setFlag(flag); } else { this.clearFlag(flag); } } /** * * @param {number|Trail2DFlags} flag * @returns {boolean} */ getFlag(flag) { return (this.flags & flag) === flag; } /** * * @param {number} segment_count */ build(segment_count) { const ribbon = new RibbonX(); ribbon.buildGeometry(); ribbon.setCount(segment_count); const geometry = ribbon.getGeometry(); const mesh = ThreeFactory.createMesh(geometry, null); this.ribbon = ribbon; this.mesh = mesh; } static fromJSON(json) { const r = new Trail2D(); r.fromJSON(json); return r; } fromJSON({ maxAge = DEFAULT_MAX_AGE, width = DEFAULT_WIDTH, textureURL, offset = Vector3.zero, color = { x: 1, y: 1, z: 1, w: 1 } }) { this.maxAge = maxAge; this.width = width; this.textureURL = textureURL; this.offset.fromJSON(offset); this.color.fromJSON(color); } toJSON() { return { maxAge: this.maxAge, width: this.width, color: this.color.toJSON(), textureURL: this.textureURL, offset: this.offset.toJSON() }; } /** * * @param {Trail2D} other */ equals(other) { return this.textureURL === other.textureURL && this.width === other.width && this.maxAge === other.maxAge && this.color.equals(other.color) && this.offset.equals(other.offset) ; } /** * * @param {number} x * @param {number} y * @param {number} z * @param {number} head_age * @returns {boolean} */ updateHead(x, y, z, head_age) { const ribbon = this.ribbon; const maxAge = this.maxAge; const refitTimeDelta = maxAge / ribbon.getCount(); let head_index = ribbon.getHeadIndex(); ribbon.getPointPosition(v3_array, head_index); const head_position_changed = x !== v3_array[0] || y !== v3_array[1] || z !== v3_array[2]; if (this.timeSinceLastUpdate >= refitTimeDelta) { if ( head_position_changed ) { // make sure that this is a new position before rotating new segment this.timeSinceLastUpdate = 0; // rotating segment ribbon.rotate(); head_index = ribbon.getHeadIndex(); } } if (head_position_changed) { ribbon.setPointPosition(head_index, x, y, z); this.setFlag(Trail2DFlags.BoundsNeedUpdate); } // set head to fresh value ribbon.setPointAttribute_Scalar(head_index, RIBBON_ATTRIBUTE_ADDRESS_AGE, head_age); ribbon.setPointAlpha(head_index, clamp01(head_age / maxAge)); ribbon.setPointThickness(head_index, this.width); return head_position_changed; } } Trail2D.typeName = "Trail2D"; Trail2D.serializable = false; Trail2D.makeGradientTrail = makeGradientTrail; export default Trail2D;