This commit is contained in:
2026-04-21 14:58:22 +08:00
parent 2f48948e43
commit e7c1611f6b
23 changed files with 748 additions and 49 deletions

View File

@ -25,7 +25,7 @@ export class AppCamera extends Monobehiver {
this.object = new ArcRotateCamera('Camera', Tools.ToRadians(70), Tools.ToRadians(85), 5, new Vector3(0, 2, 0), scene);
this.object.attachControl(canvas, true);
this.object.minZ = 0.01; // 近裁剪面
this.object.wheelPrecision =999999; // 滚轮缩放精度
// this.object.wheelPrecision =999999; // 滚轮缩放精度
this.object.panningSensibility = 0;
// 限制垂直角范围,实现上帝视角

173
src/babylonjs/AppHotspot.ts Normal file
View File

@ -0,0 +1,173 @@
import { Vector3 } from '@babylonjs/core'
import { Monobehiver } from '../base/Monobehiver'
import { HotSpot, HotspotPrams, Point } from '../hotspot'
// import { userSellingPointStore } from '@/stores/zguiy'
import type { MainApp } from './MainApp'
import { Dictionary } from '../utils/Dictionary'
import { EventBridge } from '../event/bridge'
export class AppHotspot extends Monobehiver {
hotSpot!: HotSpot
sllingPointStore: any
//偏移量
offset: number = 0.7
yundong: boolean = false
hotspotDic: Dictionary<HotSpot> = new Dictionary()
constructor(mainApp: MainApp) {
super(mainApp)
// this.sllingPointStore = userSellingPointStore()
}
Awake() {
const hotspot = new HotSpot(this.mainApp)
hotspot.Awake()
this.hotSpot = hotspot;
// 注意:需要从外部传入热点列表,或者从配置中读取
// this.initHotSpot(hotSpotList)
}
render(hotSpotList: Array<any>) {
// 确保 hotSpot 已初始化
if (!this.hotSpot) {
this.Awake();
}
this.initHotSpot(hotSpotList);
}
initHotSpot(hotSpotList: Array<any>) {
hotSpotList.forEach((hotspot: any) => {
this.createHotspot(hotspot)
});
}
createHotspot(hotspot: any) {
// 检查必要的数据
if (!hotspot) {
console.warn('热点数据为空');
return;
}
console.log('热点原始数据:', hotspot);
let position: Vector3;
// 使用 offset 作为 position
if (hotspot.offset) {
if (Array.isArray(hotspot.offset)) {
console.log('offset 数组:', hotspot.offset);
position = new Vector3(
hotspot.offset[0] ?? 0,
hotspot.offset[1] ?? 0,
hotspot.offset[2] ?? 0
);
} else {
position = new Vector3(
hotspot.offset.x ?? 0,
hotspot.offset.y ?? 0,
hotspot.offset.z ?? 0
);
}
} else if (hotspot.position) {
// 兼容 position 字段
if (Array.isArray(hotspot.position)) {
position = new Vector3(
hotspot.position[0] ?? 0,
hotspot.position[1] ?? 0,
hotspot.position[2] ?? 0
);
} else {
position = new Vector3(
hotspot.position.x ?? 0,
hotspot.position.y ?? 0,
hotspot.position.z ?? 0
);
}
} else {
console.warn('热点数据缺少 position 或 offset 字段:', hotspot);
return;
}
console.log('创建热点:', hotspot.name, 'position:', position, 'x:', position.x, 'y:', position.y, 'z:', position.z);
const disposition = Vector3.Zero();
this.hotSpot.Point_Event(
new HotspotPrams(
position,
disposition,
() => {
},
async (p: Point) => {
console.log('热点被点击:', hotspot.name, hotspot.payload)
// 触发热点点击事件
EventBridge.hotspotClick({
id: hotspot.id,
name: hotspot.name,
meshName: hotspot.meshName,
payload: hotspot.payload
})
},
hotspot.icon,
hotspot.radius
)
)
}
clean() {
// 首先隐藏所有热点
this.visible(false);
// 如果存在热点池
if (this.hotSpot && this.hotSpot._point_Pool && this.hotSpot._point_Pool.points) {
// 遍历所有热点
for (let i = 0; i < this.hotSpot._point_Pool.points.length; i++) {
const point = this.hotSpot._point_Pool.points[i];
// 清除事件监听器
if (point.img && point.onCallBack) {
point.img.removeEventListener('mousedown', point.onCallBack);
}
// 从DOM中移除注释元素
if (point.annotation && point.annotation.parentNode) {
point.annotation.parentNode.removeChild(point.annotation);
}
// 释放sprite资源
if (point.sprite) {
point.sprite.dispose();
}
}
// 清空热点池
this.hotSpot._point_Pool.points = [];
}
console.log('热点资源已释放');
}
visible(visible: boolean) {
console.log(visible);
if (this.hotSpot) {
this.hotSpot.Enable_All(visible)
}
}
}

View File

@ -71,6 +71,15 @@ class AppRay extends Monobehiver {
// 处理单击
handleSingleClick(evt: IPointerEvent, pickInfo: PickingInfo | null) {
// 先尝试热点mesh 热点 / sprite 热点)
// if (pickInfo && pickInfo.pickedMesh) {
// const isHotspotClick = this.mainApp.appHotspot?.handlePick(pickInfo.pickedMesh);
// if (isHotspotClick) return;
// }
// const isSpriteHotspotClick = this.mainApp.appHotspot?.handleSpritePick();
// if (isSpriteHotspotClick) return;
if (pickInfo && pickInfo.pickedMesh) {
EventBridge.modelClick({
meshName: pickInfo.pickedMesh.name,
@ -125,18 +134,7 @@ class AppRay extends Monobehiver {
* @param hotspots 热点数据
*/
renderHotspots(hotspots: any[]): void {
console.log('Rendering hotspots:', hotspots);
// 这里需要根据实际的热点渲染逻辑实现
// 示例实现:
// 1. 清除现有的热点
// 2. 根据热点数据创建新的热点标记
// 3. 为热点添加交互事件
hotspots.forEach((hotspot, index) => {
console.log(`Rendering hotspot ${index}:`, hotspot);
// 这里需要根据实际的热点数据结构实现
});
this.mainApp.appHotspot?.render(hotspots);
}
}

View File

@ -1,4 +1,4 @@
import { Mesh, PBRMaterial, Texture, AbstractMesh, Plane, Vector3, Scene, Color3 } from "@babylonjs/core";
import { Mesh, PBRMaterial, Texture, AbstractMesh, Plane, Vector3, Scene, Color3, TransformNode } from "@babylonjs/core";
import { Observer } from "@babylonjs/core/Misc/observable";
import { Nullable } from "@babylonjs/core/types";
import { Monobehiver } from '../base/Monobehiver';
@ -441,10 +441,10 @@ export class GameManager extends Monobehiver {
this.rollerDoorGroup!.position.y = next;
// 打印每个卷帘门的当前位置
console.log('Roller door positions:');
for (const mesh of this.rollerDoorMeshes) {
console.log(`${mesh.name}: ${mesh.position.y.toFixed(2)}`);
}
// console.log('Roller door positions:');
// for (const mesh of this.rollerDoorMeshes) {
// console.log(`${mesh.name}: ${mesh.position.y.toFixed(2)}`);
// }
});
}
@ -544,8 +544,8 @@ export class GameManager extends Monobehiver {
// 创建或获取 group 作为父级
if (!this.rollerDoorGroup) {
// 创建一个 AbstractMesh 作为组
this.rollerDoorGroup = new AbstractMesh('rollerDoorGroup', scene);
// 确保 group 的缩放为 1
// 使用 TransformNode 代替 AbstractMesh因为 AbstractMesh 是抽象类无法实例化
this.rollerDoorGroup = new TransformNode('rollerDoorGroup', scene) as any;
// 确保 group 的初始位置为 (0, 0, 0)
this.rollerDoorGroup.position.set(0, 0, 0);
}

View File

@ -13,6 +13,7 @@ import { AppConfig } from './AppConfig';
import { AppRay } from './AppRay';
import { GameManager } from './GameManager';
import { EventBridge } from '../event/bridge';
import { AppHotspot } from './AppHotspot';
/**
* 主应用类 - 3D场景的核心控制器
@ -26,6 +27,7 @@ export class MainApp {
appLight: AppLight;
appEnv: AppEnv;
appRay: AppRay;
appHotspot: AppHotspot;
gameManager: GameManager;
@ -37,6 +39,7 @@ export class MainApp {
this.appLight = new AppLight(this);
this.appEnv = new AppEnv(this);
this.appRay = new AppRay(this);
this.appHotspot = new AppHotspot(this);
this.gameManager = new GameManager(this);
window.addEventListener("resize", () => this.appEngin.handleResize());
@ -84,5 +87,6 @@ export class MainApp {
async dispose(): Promise<void> {
this.appModel?.clean();
this.appEnv?.clean();
this.appHotspot?.clear();
}
}