UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

178 lines (132 loc) 5.35 kB
import { BufferGeometry, Float32BufferAttribute, Line, LineBasicMaterial } from "three"; import { SurfacePoint3 } from "../../../src/core/geom/3d/SurfacePoint3.js"; import Vector3 from "../../../src/core/geom/Vector3.js"; import { max2 } from "../../../src/core/math/max2.js"; import { min2 } from "../../../src/core/math/min2.js"; import { ProcessState } from "../../../src/core/process/ProcessState.js"; import Task from "../../../src/core/process/task/Task.js"; import { TaskSignal } from "../../../src/core/process/task/TaskSignal.js"; import Entity from "../../../src/engine/ecs/Entity.js"; import { EventType } from "../../../src/engine/ecs/EventType.js"; import Renderable from "../../../src/engine/ecs/renderable/Renderable.js"; import { obtainTerrain } from "../../../src/engine/ecs/terrain/util/obtainTerrain.js"; import { Transform } from "../../../src/engine/ecs/transform/Transform.js"; import GridPosition from "../../../src/engine/grid/position/GridPosition.js"; import EditorEntity from "../../ecs/EditorEntity.js"; import { make3DSymbolicDisplay } from "./make3DSymbolicDisplay.js"; /** * * @param {Engine} engine */ export function makeGridPositionSymbolDisplay(engine) { /** * * @type {EntityManager} */ const em = engine.entityManager; const updateQueue = []; const tTerrainWaiter = new Task({ name: 'terrain-waiter', cycleFunction() { if (updateQueue.length === 0) { return TaskSignal.Yield; } const f = updateQueue.shift(); f(); return TaskSignal.Continue; } }); /** * * @param {GridPosition} gridPosition * @param {Transform} transform * @returns {Entity} */ function makeHelper(gridPosition, transform) { const builder = new Entity(); // TODO replace with {@link VisualSymbolLine} const lineMaterial = new LineBasicMaterial({ color: 0xFFFFFF }); lineMaterial.depthTest = false; const lineGeometry = new BufferGeometry(); const positionAttribute = new Float32BufferAttribute(new Float32Array(6), 3); lineGeometry.setAttribute('position', positionAttribute); //find terrain const terrain = obtainTerrain(em.dataset); const line = new Line(lineGeometry, lineMaterial); line.updateMatrixWorld(); line.frustumCulled = false; const renderable = new Renderable(line); renderable.matrixAutoUpdate = false; const contact = new SurfacePoint3(); const p0 = transform.position; const p1 = new Vector3(); /** * * @returns {boolean} */ function updateGridPosition() { //get grid position in the world terrain.mapPointGrid2World(gridPosition.x, gridPosition.y, p1); return terrain.raycastFirstSync(contact, p1.x, -(terrain.heightRange + 1), p1.z, 0, 1, 0); } function updateGeometry() { const c = contact.position; positionAttribute.setXYZ(0, p0.x, p0.y, p0.z); positionAttribute.setXYZ(1, c.x, c.y, c.z); positionAttribute.needsUpdate = true; } function updateBounds() { const c = contact.position; const x0 = min2(p0.x, c.x), y0 = min2(p0.y, c.y), z0 = min2(p0.z, c.z), x1 = max2(p0.x, c.x), y1 = max2(p0.y, c.y), z1 = max2(p0.z, c.z); renderable.boundingBox.setBounds(x0, y0, z0, x1, y1, z1); renderable.bvh.resize(x0, y0, z0, x1, y1, z1); } function attemptUpdate() { if (updateGridPosition()) { updateGeometry(); updateBounds(); } else if (updateQueue.indexOf(attemptUpdate) === -1) { updateQueue.push(attemptUpdate); } } attemptUpdate(); builder .add(renderable) .add(new Transform()) .add(new EditorEntity()); builder.addEventListener(EventType.EntityRemoved, () => { p0.onChanged.remove(attemptUpdate); gridPosition.onChanged.remove(attemptUpdate); }); builder.on.built.add(() => { p0.onChanged.add(attemptUpdate); gridPosition.onChanged.add(attemptUpdate); attemptUpdate(); }); return builder; } const display = make3DSymbolicDisplay({ engine, components: [GridPosition, Transform], factory([gridPosition, transform, entity], api) { api.emit(makeHelper(gridPosition, transform)); } }); display.__state.onChanged.add((s0, s1) => { if (s0 === ProcessState.Running) { //started engine.executor.run(tTerrainWaiter); } else if (s1 === ProcessState.Running) { //stopepd engine.executor.removeTask(tTerrainWaiter); //purge update queue updateQueue.splice(0, updateQueue.length); } }); return display; }