TkAstral3D/packages/sdk/lib/core/tools/MiniMap-20240823.ts
2025-10-04 23:36:07 +08:00

123 lines
3.6 KiB
TypeScript

import * as THREE from "three";
import {MapControls} from "three/examples/jsm/controls/MapControls.js";
interface IMiniMapOptions {
domElement?: HTMLElement;
}
let onPointerDownFn;
export class MiniMap {
private viewport;
private mapControl: MapControls;
private domElement: HTMLElement;
private miniMapRenderer: THREE.WebGLRenderer;
private miniMapCamera: THREE.PerspectiveCamera;
raycaster = new THREE.Raycaster()
constructor(viewport,options:IMiniMapOptions = {}) {
this.viewport = viewport;
this.domElement = options.domElement || this.createDomElement();
viewport.container.appendChild(this.domElement);
const {renderer, camera} = this.init();
this.miniMapRenderer = renderer;
this.miniMapCamera = camera;
this.mapControl = this.initControls();
this.initEvent();
this.miniMapRenderer.setAnimationLoop(this.miniMapAnimation.bind(this));
}
createDomElement(){
const domElement = document.createElement("div");
domElement.setAttribute("id", "es-3d-mini-map");
domElement.style.position = "absolute";
domElement.style.top = "10px";
domElement.style.right = "10px";
domElement.style.width = "250px";
domElement.style.height = "250px";
domElement.style.boxShadow = "0px 0px 5px #000";
return domElement;
}
/**
* 为小地图准备专门的 渲染器 + 摄像机
*/
init(){
const miniMapRenderer = new THREE.WebGLRenderer({antialias:true});
miniMapRenderer.setSize(this.domElement.clientWidth, this.domElement.clientHeight);
this.domElement.appendChild(miniMapRenderer.domElement);
miniMapRenderer.setClearColor(0xffffff);
const miniMapCamera = new THREE.PerspectiveCamera(
45,
this.domElement.clientWidth / this.domElement.clientHeight,
0.1,
1000
)
miniMapCamera.position.set(0, 50, 0)
miniMapCamera.lookAt(0,0,0);
return {
renderer: miniMapRenderer,
camera: miniMapCamera
}
}
initControls() {
const controls = new MapControls(this.miniMapCamera, this.miniMapRenderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.enableZoom = false;
return controls;
}
initEvent(){
onPointerDownFn = this.onPointerDown.bind(this);
this.domElement.addEventListener("pointerdown", onPointerDownFn);
}
onPointerDown(e: PointerEvent){
const mousePosition = new THREE.Vector2()
let x = e.offsetX
let y = e.offsetY
mousePosition.x = ((x / this.domElement.clientWidth) * 2) - 1;
mousePosition.y = -((y / this.domElement.clientHeight) * 2) + 1;
this.raycaster.setFromCamera(mousePosition, this.miniMapCamera);
let intersections = this.raycaster.intersectObject(this.viewport.scene, true);
if(intersections[0]){
const point = intersections[0].point;
// this.miniMapCamera.position.set(point.x, 8, point.z);
this.viewport.modules.controls.target.set(point.x, 0, point.z);
}
}
miniMapAnimation(){
this.miniMapRenderer.render(this.viewport.scene, this.miniMapCamera)
}
update(){
this.mapControl.update();
}
dispose(){
this.mapControl.dispose();
this.miniMapRenderer.dispose();
this.domElement.removeChild(this.miniMapRenderer.domElement);
this.domElement.removeEventListener("pointerdown", onPointerDownFn);
onPointerDownFn = null;
}
}