123 lines
3.6 KiB
TypeScript
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;
|
|
}
|
|
} |