130 lines
4.3 KiB
TypeScript
130 lines
4.3 KiB
TypeScript
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} |