UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

212 lines (161 loc) • 5.63 kB
import View from "../../View.js"; import Vector3 from "../../../core/geom/Vector3.js"; import ObservedValue from "../../../core/model/ObservedValue.js"; import { SurfacePoint3 } from "../../../core/geom/3d/SurfacePoint3.js"; import SVG from "../../SVG.js"; import { plane3_compute_ray_intersection } from "../../../core/geom/3d/plane/plane3_compute_ray_intersection.js"; const rayContact = new SurfacePoint3(); export class MinimapCameraView extends View { /** * * @param {Camera} camera * @param {Transform} transform * @param entity * @param {Rectangle} world * @param {Vector2} worldScale * @constructor */ constructor({ camera, transform, entity, world, worldScale }) { super(); this.el = SVG.createElement('svg'); this.addClass('ui-camera-view'); /** * * @type {Element} * @private */ this.__el_polygon = SVG.createElement('polygon'); this.el.appendChild(this.__el_polygon); /** * * @type {Camera} */ this.camera = camera; /** * * @type {Transform} */ this.transform = transform; this.entity = entity; /** * * @type {Rectangle} * @private */ this.__world = world; /** * * @type {Vector2} * @private */ this.__world_scale = worldScale; /** * * @type {ObservedValue<Terrain>} */ this.terrain = new ObservedValue(null); this .bindSignal(this.camera.projectionType.onChanged, this.__update, this) .bindSignal(this.transform.position.onChanged, this.__update, this) .bindSignal(worldScale.onChanged, this.__update, this) .bindSignal(world.position.onChanged, this.__update, this) .bindSignal(this.transform.rotation.onChanged, this.__update, this); } /** * * @param {Vector3} result * @param {number} originX * @param {number} originY * @param {number} originZ * @param {number} directionX * @param {number} directionY * @param {number} directionZ */ castTerrainRay(result, originX, originY, originZ, directionX, directionY, directionZ) { const terrain = this.terrain.getValue(); const JITTER = 0.00001; if (terrain === null) { plane3_compute_ray_intersection(result, originX, originY, originZ, directionX, directionY, directionZ, 0, 1, 0, 0); } else { let oX = originX; let oY = originY; let oZ = originZ; let foundHit = false; for (let i = 0; i < 10 && !foundHit; i++) { foundHit = terrain.raycastFirstSync(rayContact, originX, originY, originZ, directionX, directionY, directionZ); if (!foundHit) { //no hit found, try to jitter origin in case of mathematical error at polygon edges oX += (Math.random() - 0.5) * JITTER; oY += (Math.random() - 0.5) * JITTER; oZ += (Math.random() - 0.5) * JITTER; } else { result.copy(rayContact.position); } } if (!foundHit) { //no hit found, fall back to planar test plane3_compute_ray_intersection(result, originX, originY, originZ, directionX, directionY, directionZ, 0, 1, 0, 0); } } } /** * * @param {number} x * @param {number} y * @returns {Vector3} */ getPoint(x, y) { const camera = this.camera; /** * * @type {Rectangle} */ const world = this.__world; /** * * @type {Vector2} */ const worldScale = this.__world_scale; const vOrigin = new Vector3(-1, 1, 0.5); const vDirection = new Vector3(1, -1, 0.5); camera.projectRay(x, y, vOrigin, vDirection); const vResult = new Vector3(0, 0, 0); this.castTerrainRay(vResult, vOrigin.x, vOrigin.y, vOrigin.z, vDirection.x, vDirection.y, vDirection.z); vResult.x -= world.position.x; vResult.x *= worldScale.x; vResult.z -= world.position.y; vResult.z *= worldScale.y; return vResult; } __update() { const camera = this.camera; /** * * @type {Transform} */ const transform = this.transform; const c = camera.object; if (c === null) { console.warn(`Camera component doesn't have three.js object built.`); return; } c.position.copy(transform.position); camera.updateMatrices(); const v_tl = this.getPoint(-1, 1); const v_tr = this.getPoint(1, 1); const v_br = this.getPoint(1, -1); const v_bl = this.getPoint(-1, -1); this.__el_polygon.setAttribute('points', `${v_tl.x},${v_tl.z} ${v_tr.x},${v_tr.z} ${v_br.x},${v_br.z} ${v_bl.x},${v_bl.z}`); }; link() { super.link(); try { this.__update(); } catch (e) { console.error('Failed to execute update', e); } } unlink() { super.unlink(); } }