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

130 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {MathUtils, OrthographicCamera, PerspectiveCamera, Scene, WebGLRenderer,Object3D} from "three";
import Viewer from "@/core/viewer/Viewer";
interface IMiniMapOptions {
mapSize: number, // 决定了摄像机看到的内容大小, mapSize * mapSize 大小内容
mapRenderSize: number, // 决定了小地图2D平面的大小
followTarget:Object3D, // 小地图画面主要跟随对象
isShow: boolean // 是否显示小地图
}
class MiniMap {
_miniMapCamera: OrthographicCamera | PerspectiveCamera | null = null;
_miniMapRenderer: WebGLRenderer | null = null;
_followTarget: Object3D;
private scene: Scene;
private sceneHelpers: Scene;
private mapRenderSize: number;
// @ts-ignore
public dom: HTMLDivElement;
isShow: boolean = false;
constructor(viewer:Viewer, options:IMiniMapOptions) {
this.scene = viewer.scene;
this.sceneHelpers = viewer.sceneHelpers;
this.mapRenderSize = options.mapRenderSize;
this._followTarget = options.followTarget;
this.isShow = options.isShow;
if (!this.scene) {
throw new Error("scene不能为空");
}
if (!this._followTarget) {
throw new Error("target不能为空表示小地图画面主要跟随对象");
}
this.dom = this.createDomElement();
viewer.container.appendChild(this.dom);
// 初始化小地图相机
this._miniMapCamera = new OrthographicCamera(
-options.mapSize / 2,
options.mapSize / 2,
options.mapSize / 2,
-options.mapSize / 2,
1, 100 * 1000
);
// 更新地图相机位置和朝向
this.updateCamera();
}
createDomElement() {
// 初始化小地图渲染器
const mapRenderer = new WebGLRenderer({alpha: true});
mapRenderer.setSize(this.mapRenderSize, this.mapRenderSize);
// mapRenderer.setClearColor(0x7d684f);
mapRenderer.shadowMap.enabled = false;
mapRenderer.autoClear = false;
this._miniMapRenderer = mapRenderer;
const pDiv = document.createElement("div");
pDiv.id = "es-3d-mini-map";
pDiv.style.position = "absolute";
pDiv.style.right = "10px";
pDiv.style.top = "10px";
pDiv.style.zIndex = "1001";
pDiv.style.border = "1px solid #FFF";
pDiv.style.background = "rgba(0, 0, 0, 0.40)";
pDiv.style.width = this.mapRenderSize - 100 + "px";
pDiv.style.height = this.mapRenderSize - 100 + "px";
pDiv.style.overflow = "hidden";
pDiv.style.display = this.isShow ? "block" : "none";
mapRenderer.domElement.style.transform = `rotateZ(0deg)`;
mapRenderer.domElement.style.width = this.mapRenderSize + "px";
mapRenderer.domElement.style.height = this.mapRenderSize + "px";
mapRenderer.domElement.style.position = "absolute";
mapRenderer.domElement.style.left = "-50px";
mapRenderer.domElement.style.top = "-50px";
pDiv.appendChild(mapRenderer.domElement);
return pDiv;
}
open(){
this.dom.style.display = "block";
this.isShow = true;
}
close(){
this.dom.style.display = "none";
this.isShow = false;
}
updateCamera() {
// 更新小地图css旋转角度与玩家同步
let targetRotateY = MathUtils.radToDeg(this._followTarget.rotation.y - Math.PI);
(this._miniMapRenderer as WebGLRenderer).domElement.style.transform = `rotateZ(${targetRotateY}deg)`;
// 更新地图相机位置和朝向
let targetPos = this._followTarget.position;
(this._miniMapCamera as OrthographicCamera).position.set(
targetPos.x,
targetPos.y + 10,
targetPos.z
);
(this._miniMapCamera as OrthographicCamera).lookAt(targetPos.x, 2, targetPos.z);
}
update() {
// 更新地图相机位置和朝向
this.updateCamera();
const renderer = this._miniMapRenderer as WebGLRenderer;
renderer.autoClear = false;
// 渲染小地图
renderer.render(this.scene, this._miniMapCamera as OrthographicCamera);
renderer.render(this.sceneHelpers, this._miniMapCamera as OrthographicCamera);
renderer.autoClear = true;
}
}
export {MiniMap}