修复bug
This commit is contained in:
@ -506,6 +506,8 @@ export class AppDropZone {
|
|||||||
*/
|
*/
|
||||||
show(): void {
|
show(): void {
|
||||||
this.placementWall.show();
|
this.placementWall.show();
|
||||||
|
// 禁用所有已放置模型的拾取
|
||||||
|
this.setModelsPickable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -514,6 +516,8 @@ export class AppDropZone {
|
|||||||
*/
|
*/
|
||||||
showWall(wallName: string): void {
|
showWall(wallName: string): void {
|
||||||
this.placementWall.showWall(wallName);
|
this.placementWall.showWall(wallName);
|
||||||
|
// 禁用所有已放置模型的拾取
|
||||||
|
this.setModelsPickable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -521,6 +525,25 @@ export class AppDropZone {
|
|||||||
*/
|
*/
|
||||||
hide(): void {
|
hide(): void {
|
||||||
this.placementWall.hide();
|
this.placementWall.hide();
|
||||||
|
// 恢复所有已放置模型的拾取
|
||||||
|
this.setModelsPickable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置所有已放置模型的可拾取状态
|
||||||
|
* @param pickable 是否可拾取
|
||||||
|
*/
|
||||||
|
private setModelsPickable(pickable: boolean): void {
|
||||||
|
if (!this.appModel) return;
|
||||||
|
|
||||||
|
this.zoneModelMap.forEach((modelId) => {
|
||||||
|
const meshes = this.appModel!.getCachedMeshes(modelId);
|
||||||
|
if (meshes && meshes.length > 0) {
|
||||||
|
meshes.forEach(mesh => {
|
||||||
|
mesh.isPickable = pickable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -114,37 +114,73 @@ export class AppModelDrag extends Monobehiver {
|
|||||||
// 使用世界坐标系而不是物体本地坐标系
|
// 使用世界坐标系而不是物体本地坐标系
|
||||||
pointerDragBehavior.useObjectOrientationForDragging = false;
|
pointerDragBehavior.useObjectOrientationForDragging = false;
|
||||||
|
|
||||||
|
// 记录拖拽起始位置和状态
|
||||||
|
let dragStartPosition: Vector3 | null = null;
|
||||||
|
let hasShownZones = false; // 是否已显示分割区域
|
||||||
|
|
||||||
// 监听拖拽开始事件
|
// 监听拖拽开始事件
|
||||||
pointerDragBehavior.onDragStartObservable.add(() => {
|
pointerDragBehavior.onDragStartObservable.add(() => {
|
||||||
|
// 记录起始位置
|
||||||
|
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
|
||||||
|
if (meshes && meshes.length > 0) {
|
||||||
|
dragStartPosition = meshes[0].position.clone();
|
||||||
|
}
|
||||||
|
|
||||||
// 禁用相机控制
|
// 禁用相机控制
|
||||||
this.disableCameraControl();
|
this.disableCameraControl();
|
||||||
|
|
||||||
// 如果启用了拖拽吸附,显示分割区域
|
// 不在这里显示分割区域,等到实际拖动时再显示
|
||||||
if (dragInfo.config.snapToZone) {
|
hasShownZones = false;
|
||||||
this.showZonesForModel(modelId);
|
});
|
||||||
|
|
||||||
|
// 监听拖拽中事件(用于边界限制和延迟显示分割区域)
|
||||||
|
pointerDragBehavior.onDragObservable.add((event) => {
|
||||||
|
// 检查是否实际移动了
|
||||||
|
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
|
||||||
|
if (meshes && meshes.length > 0 && dragStartPosition) {
|
||||||
|
const distance = Vector3.Distance(dragStartPosition, meshes[0].position);
|
||||||
|
|
||||||
|
// 如果移动距离超过阈值且还没显示分割区域,则显示
|
||||||
|
if (distance > 0.01 && !hasShownZones && dragInfo.config.snapToZone) {
|
||||||
|
this.showZonesForModel(modelId);
|
||||||
|
hasShownZones = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用边界限制
|
||||||
|
if (dragInfo.config.boundaryConstraint) {
|
||||||
|
this.applyBoundaryConstraint(modelId, event.dragPlanePoint);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听拖拽中事件(用于边界限制)
|
|
||||||
if (dragInfo.config.boundaryConstraint) {
|
|
||||||
pointerDragBehavior.onDragObservable.add((event) => {
|
|
||||||
this.applyBoundaryConstraint(modelId, event.dragPlanePoint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听拖拽结束事件
|
// 监听拖拽结束事件
|
||||||
pointerDragBehavior.onDragEndObservable.add(() => {
|
pointerDragBehavior.onDragEndObservable.add(() => {
|
||||||
|
// 检查是否实际移动了
|
||||||
|
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
|
||||||
|
let hasMoved = false;
|
||||||
|
if (meshes && meshes.length > 0 && dragStartPosition) {
|
||||||
|
const distance = Vector3.Distance(dragStartPosition, meshes[0].position);
|
||||||
|
hasMoved = distance > 0.01; // 移动距离大于 0.01 才算拖拽
|
||||||
|
}
|
||||||
|
|
||||||
// 恢复相机控制
|
// 恢复相机控制
|
||||||
this.enableCameraControl();
|
this.enableCameraControl();
|
||||||
|
|
||||||
// 如果启用了拖拽吸附,隐藏分割区域并吸附到最近区域
|
// 只有在实际移动的情况下才执行拖拽逻辑
|
||||||
if (dragInfo.config.snapToZone) {
|
if (hasMoved) {
|
||||||
this.hideZonesForModel(modelId);
|
// 如果启用了拖拽吸附,隐藏分割区域并吸附到最近区域
|
||||||
this.snapModelToZone(modelId);
|
if (dragInfo.config.snapToZone && hasShownZones) {
|
||||||
} else {
|
this.hideZonesForModel(modelId);
|
||||||
// 否则只更新映射关系
|
this.snapModelToZone(modelId);
|
||||||
this.updateModelZoneMapping(modelId);
|
} else {
|
||||||
|
// 否则只更新映射关系
|
||||||
|
this.updateModelZoneMapping(modelId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清除状态
|
||||||
|
dragStartPosition = null;
|
||||||
|
hasShownZones = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return pointerDragBehavior;
|
return pointerDragBehavior;
|
||||||
|
|||||||
@ -21,6 +21,11 @@ class AppRay extends Monobehiver {
|
|||||||
private highlightLayer: HighlightLayer | null = null
|
private highlightLayer: HighlightLayer | null = null
|
||||||
private originalMaterial: any = null
|
private originalMaterial: any = null
|
||||||
private highlightedMesh: AbstractMesh | null = null
|
private highlightedMesh: AbstractMesh | null = null
|
||||||
|
private pointerDownTime: number = 0
|
||||||
|
private pointerDownPickInfo: PickingInfo | null = null
|
||||||
|
private longPressTimer: any = null
|
||||||
|
private longPressThreshold: number = 500 // 长按阈值(毫秒)
|
||||||
|
private isLongPress: boolean = false
|
||||||
|
|
||||||
constructor(mainApp: MainApp) {
|
constructor(mainApp: MainApp) {
|
||||||
super(mainApp)
|
super(mainApp)
|
||||||
@ -58,18 +63,91 @@ class AppRay extends Monobehiver {
|
|||||||
|
|
||||||
if (type === PointerEventTypes.POINTERDOWN) {
|
if (type === PointerEventTypes.POINTERDOWN) {
|
||||||
this.oldPoint.set(pointerEvent.clientX, 0, pointerEvent.clientY);
|
this.oldPoint.set(pointerEvent.clientX, 0, pointerEvent.clientY);
|
||||||
|
this.pointerDownTime = Date.now();
|
||||||
|
this.pointerDownPickInfo = pickInfo;
|
||||||
|
this.isLongPress = false;
|
||||||
|
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置长按定时器
|
||||||
|
this.longPressTimer = setTimeout(() => {
|
||||||
|
this.isLongPress = true;
|
||||||
|
this.handleLongPress(pointerEvent, this.pointerDownPickInfo);
|
||||||
|
}, this.longPressThreshold);
|
||||||
|
|
||||||
} else if (type === PointerEventTypes.POINTERUP) {
|
} else if (type === PointerEventTypes.POINTERUP) {
|
||||||
|
// 清除长按定时器
|
||||||
|
if (this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.newPoint.set(pointerEvent.clientX, 0, pointerEvent.clientY);
|
this.newPoint.set(pointerEvent.clientX, 0, pointerEvent.clientY);
|
||||||
const distance = Vector3.Distance(this.oldPoint, this.newPoint);
|
const distance = Vector3.Distance(this.oldPoint, this.newPoint);
|
||||||
|
|
||||||
// 只有在没有移动的情况下才处理单击
|
// 只有在没有移动且不是长按的情况下才处理单击
|
||||||
if (distance < 5) { // 增加一些容差
|
if (distance < 5 && !this.isLongPress) {
|
||||||
this.handleSingleClick(pointerEvent, pickInfo);
|
this.handleSingleClick(pointerEvent, pickInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isLongPress = false;
|
||||||
|
} else if (type === PointerEventTypes.POINTERMOVE) {
|
||||||
|
// 如果移动了,取消长按
|
||||||
|
this.newPoint.set(pointerEvent.clientX, 0, pointerEvent.clientY);
|
||||||
|
const distance = Vector3.Distance(this.oldPoint, this.newPoint);
|
||||||
|
if (distance > 5 && this.longPressTimer) {
|
||||||
|
clearTimeout(this.longPressTimer);
|
||||||
|
this.longPressTimer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理长按
|
||||||
|
handleLongPress(evt: IPointerEvent, pickInfo: PickingInfo | null) {
|
||||||
|
if (pickInfo && pickInfo.hit && pickInfo.pickedMesh) {
|
||||||
|
// 检查是否长按的是模型(不是放置区域、不是热点)
|
||||||
|
if (pickInfo.pickedMesh.metadata?.type === 'hotspot') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pickInfo.pickedMesh.name.startsWith('placement_')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取模型名称
|
||||||
|
const modelName = this.mainApp.appModel.findModelNameByMesh(pickInfo.pickedMesh);
|
||||||
|
if (modelName) {
|
||||||
|
// 通过模型找到它所在的墙面
|
||||||
|
const wallName = this.findModelWallName(modelName);
|
||||||
|
if (wallName) {
|
||||||
|
console.log(`[长按] 模型 ${modelName} 位于墙面 ${wallName},显示该墙面的放置区域`);
|
||||||
|
this.mainApp.appDropZone.showWall(wallName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找模型所在的墙面
|
||||||
|
private findModelWallName(modelId: string): string | null {
|
||||||
|
const zoneModelMap = this.mainApp.appDropZone['zoneModelMap'] as Map<string, string>;
|
||||||
|
if (!zoneModelMap) return null;
|
||||||
|
|
||||||
|
for (const [zoneKey, id] of zoneModelMap.entries()) {
|
||||||
|
if (id === modelId) {
|
||||||
|
// zoneKey 格式为 "wallName[index]"
|
||||||
|
const match = zoneKey.match(/^(.+)\[(\d+)\]$/);
|
||||||
|
if (match) {
|
||||||
|
return match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// 处理单击
|
// 处理单击
|
||||||
handleSingleClick(evt: IPointerEvent, pickInfo: PickingInfo | null) {
|
handleSingleClick(evt: IPointerEvent, pickInfo: PickingInfo | null) {
|
||||||
// 先尝试热点(mesh 热点 / sprite 热点)
|
// 先尝试热点(mesh 热点 / sprite 热点)
|
||||||
@ -93,7 +171,7 @@ class AppRay extends Monobehiver {
|
|||||||
const clickedZone = zones.find(zone => zone.mesh === pickInfo.pickedMesh);
|
const clickedZone = zones.find(zone => zone.mesh === pickInfo.pickedMesh);
|
||||||
if (clickedZone) {
|
if (clickedZone) {
|
||||||
// 计算该放置区域的目标位置和旋转
|
// 计算该放置区域的目标位置和旋转
|
||||||
const offsetDistance = 0; // 增加偏移距离,让模型更往外
|
const offsetDistance = 0;
|
||||||
const targetPosition = clickedZone.center.add(clickedZone.normal.scale(offsetDistance));
|
const targetPosition = clickedZone.center.add(clickedZone.normal.scale(offsetDistance));
|
||||||
const targetDirection = clickedZone.normal.scale(-1);
|
const targetDirection = clickedZone.normal.scale(-1);
|
||||||
const angle = Math.atan2(targetDirection.x, targetDirection.z);
|
const angle = Math.atan2(targetDirection.x, targetDirection.z);
|
||||||
@ -114,7 +192,7 @@ class AppRay extends Monobehiver {
|
|||||||
},
|
},
|
||||||
rotation: {
|
rotation: {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: angle * 180 / Math.PI, // 转换为角度
|
y: angle * 180 / Math.PI,
|
||||||
z: 0
|
z: 0
|
||||||
},
|
},
|
||||||
scale: {
|
scale: {
|
||||||
@ -130,6 +208,9 @@ class AppRay extends Monobehiver {
|
|||||||
|
|
||||||
this.mainApp.appDomTo3D.hideAll()
|
this.mainApp.appDomTo3D.hideAll()
|
||||||
|
|
||||||
|
// 隐藏放置区域,避免遮挡配件模型的点击
|
||||||
|
this.mainApp.appDropZone.hide();
|
||||||
|
|
||||||
const materialName = pickInfo.pickedMesh.material?.name || '';
|
const materialName = pickInfo.pickedMesh.material?.name || '';
|
||||||
const holdingShift = Boolean((evt as any).shiftKey);
|
const holdingShift = Boolean((evt as any).shiftKey);
|
||||||
const modelMeshes = this.mainApp.appModel.getModelMeshesByMesh(pickInfo.pickedMesh);
|
const modelMeshes = this.mainApp.appModel.getModelMeshesByMesh(pickInfo.pickedMesh);
|
||||||
|
|||||||
Reference in New Issue
Block a user