1
This commit is contained in:
65
index.html
65
index.html
@ -453,7 +453,7 @@
|
||||
<div class="category-content expanded">
|
||||
<div class="option-group">
|
||||
<button class="option-btn" data-option="color-1">SPFPDS13FTW</button>
|
||||
<button class="option-btn" data-option="color-2">SPFPDS13FTC</button>
|
||||
<button class="option-btn" data-option="color-2">SPFSW13FTC</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -911,23 +911,62 @@
|
||||
|
||||
// 生成放置区域按钮事件
|
||||
let dropZoneVisible = false;
|
||||
document.getElementById('dropzone-btn').addEventListener('click', () => {
|
||||
if (!dropZoneVisible) {
|
||||
document.getElementById('dropzone-btn').addEventListener('click', async () => {
|
||||
|
||||
const { wallName, index } = dropzone_data;
|
||||
|
||||
// 先正常放置模型
|
||||
await window.AppLogic.getEvent(dropzone_data, sku);
|
||||
|
||||
// 更新按钮文字
|
||||
document.getElementById('dropzone-btn').textContent = '隐藏放置区域';
|
||||
console.log('已生成并显示放置区域');
|
||||
} else {
|
||||
// 隐藏放置区域
|
||||
kernel.dropZone.hideAll();
|
||||
dropZoneVisible = false;
|
||||
// 检查该墙面是否已满
|
||||
const zones = kernel.dropZone.getPlacementZones();
|
||||
const wallZones = zones.filter(z => z.wallName === wallName);
|
||||
|
||||
// 更新按钮文字
|
||||
document.getElementById('dropzone-btn').textContent = '生成放置区域';
|
||||
console.log('已隐藏放置区域');
|
||||
// 获取该墙面已放置的模型
|
||||
const placedModels = kernel.dropZone.getPlacedModels(wallName);
|
||||
|
||||
// 如果该墙面所有区域都已占用
|
||||
if (placedModels.length === wallZones.length) {
|
||||
console.log(`${wallName} 墙面已满,自动排列模型`);
|
||||
|
||||
// 按区域索引排序
|
||||
const sortedZones = wallZones.sort((a, b) => a.index - b.index);
|
||||
|
||||
// 重新排列模型到对应区域
|
||||
placedModels.forEach((model, idx) => {
|
||||
const targetZone = sortedZones[idx];
|
||||
const { position, rotation } = targetZone.transform;
|
||||
|
||||
// 移动模型到目标位置
|
||||
kernel.transform.position({
|
||||
modelId: model.modelId,
|
||||
vector3: position
|
||||
});
|
||||
|
||||
kernel.transform.rotation({
|
||||
modelId: model.modelId,
|
||||
vector3: rotation
|
||||
});
|
||||
|
||||
// 禁用该模型的拖拽
|
||||
kernel.model.setDragEnabled(model.modelId, false);
|
||||
});
|
||||
|
||||
console.log('模型已自动排列并禁用拖拽');
|
||||
}
|
||||
// if (!dropZoneVisible) {
|
||||
// // 更新按钮文字
|
||||
// document.getElementById('dropzone-btn').textContent = '隐藏放置区域';
|
||||
// console.log('已生成并显示放置区域');
|
||||
// } else {
|
||||
// // 隐藏放置区域
|
||||
// kernel.dropZone.hideAll();
|
||||
// dropZoneVisible = false;
|
||||
|
||||
// // 更新按钮文字
|
||||
// document.getElementById('dropzone-btn').textContent = '生成放置区域';
|
||||
// console.log('已隐藏放置区域');
|
||||
// }
|
||||
});
|
||||
|
||||
// 初始化放置区域配置数据(只需设置一次)
|
||||
|
||||
@ -21,6 +21,7 @@ export class AppDropZone {
|
||||
private scene: Scene;
|
||||
private placementWall: AppPlacementWall;
|
||||
private appModel: AppModel | null = null;
|
||||
private mainApp: any = null;
|
||||
|
||||
// 内部映射:放置区域 -> 模型ID
|
||||
private zoneModelMap: Map<string, string> = new Map();
|
||||
@ -46,6 +47,13 @@ export class AppDropZone {
|
||||
this.appModel = appModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 MainApp 引用(内部使用)
|
||||
*/
|
||||
setMainApp(mainApp: any): void {
|
||||
this.mainApp = mainApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置放置区域数据
|
||||
* @param config 配置参数
|
||||
@ -236,6 +244,235 @@ export class AppDropZone {
|
||||
// 记录新模型
|
||||
this.zoneModelMap.set(zoneKey, modelId);
|
||||
console.log(`已记录模型 ${modelId} 到区域 ${zoneKey}`);
|
||||
|
||||
// 检查该墙面是否已满,如果满了则自动排列
|
||||
this.checkAndAutoArrange(wallName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知模型被删除(外部调用,用于更新映射和重新启用拖拽)
|
||||
* @param modelId 被删除的模型ID
|
||||
*/
|
||||
notifyModelRemoved(modelId: string): void {
|
||||
console.log(`[模型删除通知] 模型 ${modelId} 被删除`);
|
||||
|
||||
// 找到该模型所在的墙面和索引
|
||||
let removedWallName: string | null = null;
|
||||
let removedZoneKey: string | null = null;
|
||||
|
||||
this.zoneModelMap.forEach((id, zoneKey) => {
|
||||
if (id === modelId) {
|
||||
removedZoneKey = zoneKey;
|
||||
// 从 zoneKey 中提取墙面名称,格式为 "wallName[index]"
|
||||
const match = zoneKey.match(/^(.+)\[(\d+)\]$/);
|
||||
if (match) {
|
||||
removedWallName = match[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (removedZoneKey) {
|
||||
// 从映射中删除
|
||||
this.zoneModelMap.delete(removedZoneKey);
|
||||
console.log(`[模型删除通知] 已从映射中删除: ${removedZoneKey}`);
|
||||
}
|
||||
|
||||
if (removedWallName) {
|
||||
// 检查该墙面是否不满了,如果不满则重新启用拖拽
|
||||
this.checkAndReenableDrag(removedWallName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查墙面是否不满,如果不满则重新启用该墙面所有模型的拖拽
|
||||
* @param wallName 墙面名称
|
||||
*/
|
||||
private checkAndReenableDrag(wallName: string): void {
|
||||
const currentDivisions = this.wallDivisionsMap.get(wallName);
|
||||
if (!currentDivisions) return;
|
||||
|
||||
// 统计该墙面已放置的模型数量
|
||||
let placedCount = 0;
|
||||
const placedModelIds: string[] = [];
|
||||
this.zoneModelMap.forEach((modelId, zoneKey) => {
|
||||
if (zoneKey.startsWith(`${wallName}[`)) {
|
||||
placedCount++;
|
||||
placedModelIds.push(modelId);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[拖拽检查] 墙面 ${wallName} 当前模型数: ${placedCount}/${currentDivisions}`);
|
||||
|
||||
// 如果墙面不满,重新启用所有模型的拖拽
|
||||
if (placedCount < currentDivisions) {
|
||||
console.log(`[拖拽检查] 墙面 ${wallName} 未满,重新启用拖拽`);
|
||||
placedModelIds.forEach(modelId => {
|
||||
if (this.mainApp && this.mainApp.appModelDrag && typeof this.mainApp.appModelDrag.setDragEnabled === 'function') {
|
||||
this.mainApp.appModelDrag.setDragEnabled(modelId, true);
|
||||
console.log(`[拖拽检查] ✓ 已启用模型 ${modelId} 的拖拽功能`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查墙面是否已满
|
||||
* @param wallName 墙面名称
|
||||
* @returns 是否已满
|
||||
*/
|
||||
isWallFull(wallName: string): boolean {
|
||||
const currentDivisions = this.wallDivisionsMap.get(wallName);
|
||||
if (!currentDivisions) return false;
|
||||
|
||||
// 统计该墙面已放置的模型数量
|
||||
let placedCount = 0;
|
||||
this.zoneModelMap.forEach((modelId, zoneKey) => {
|
||||
if (zoneKey.startsWith(`${wallName}[`)) {
|
||||
placedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
return placedCount >= currentDivisions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查墙面是否已满,如果满了则自动排列模型
|
||||
* @param wallName 墙面名称
|
||||
*/
|
||||
private checkAndAutoArrange(wallName: string): void {
|
||||
const currentDivisions = this.wallDivisionsMap.get(wallName);
|
||||
console.log(`[自动排列检查] 墙面: ${wallName}, 分割数: ${currentDivisions}`);
|
||||
|
||||
if (!currentDivisions) {
|
||||
console.log(`[自动排列检查] 墙面 ${wallName} 没有分割数配置,跳过`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 统计该墙面已放置的模型数量
|
||||
let placedCount = 0;
|
||||
const placedModels: string[] = [];
|
||||
this.zoneModelMap.forEach((modelId, zoneKey) => {
|
||||
if (zoneKey.startsWith(`${wallName}[`)) {
|
||||
placedCount++;
|
||||
placedModels.push(`${zoneKey} -> ${modelId}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[自动排列检查] 墙面 ${wallName} 已放置模型数: ${placedCount}/${currentDivisions}`);
|
||||
console.log(`[自动排列检查] 已放置的模型:`, placedModels);
|
||||
|
||||
// 如果该墙面已满(放置数量等于分割数),执行自动排列
|
||||
if (placedCount === currentDivisions) {
|
||||
console.log(`[自动排列] 墙面 ${wallName} 已满(${placedCount}/${currentDivisions}),开始执行自动排列`);
|
||||
this.autoArrangeWall(wallName);
|
||||
} else {
|
||||
console.log(`[自动排列检查] 墙面 ${wallName} 未满,不执行自动排列`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动排列墙面上的所有模型
|
||||
* @param wallName 墙面名称
|
||||
*/
|
||||
private autoArrangeWall(wallName: string): void {
|
||||
console.log(`[自动排列] 开始排列墙面: ${wallName}`);
|
||||
|
||||
// 获取该墙面的所有放置区域
|
||||
const wallZones = this.getZonesByWall(wallName);
|
||||
console.log(`[自动排列] 墙面 ${wallName} 的放置区域数量: ${wallZones.length}`);
|
||||
|
||||
if (!wallZones.length) {
|
||||
console.log(`[自动排列] 墙面 ${wallName} 没有放置区域,退出`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 收集该墙面已放置的模型信息
|
||||
const placedModels: Array<{ modelId: string; currentIndex: number }> = [];
|
||||
this.zoneModelMap.forEach((modelId, zoneKey) => {
|
||||
const match = zoneKey.match(new RegExp(`^${wallName}\\[(\\d+)\\]$`));
|
||||
if (match) {
|
||||
const currentIndex = parseInt(match[1]);
|
||||
placedModels.push({
|
||||
modelId: modelId,
|
||||
currentIndex: currentIndex
|
||||
});
|
||||
console.log(`[自动排列] 找到模型: ${modelId}, 当前索引: ${currentIndex}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[自动排列] 收集到 ${placedModels.length} 个模型`);
|
||||
|
||||
// 按当前索引排序
|
||||
placedModels.sort((a, b) => a.currentIndex - b.currentIndex);
|
||||
console.log(`[自动排列] 排序后的模型顺序:`, placedModels.map(m => `${m.modelId}(索引${m.currentIndex})`));
|
||||
|
||||
// 重新排列:将模型按顺序放置到 0, 1, 2... 的位置
|
||||
placedModels.forEach((model, newIndex) => {
|
||||
console.log(`[自动排列] 处理模型 ${model.modelId}: 当前索引=${model.currentIndex}, 目标索引=${newIndex}`);
|
||||
|
||||
// 获取目标放置区域
|
||||
const targetZone = wallZones[newIndex];
|
||||
if (!targetZone) {
|
||||
console.warn(`[自动排列] ✗ 找不到索引 ${newIndex} 的放置区域`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.appModel) {
|
||||
// 计算新位置(从放置区域的中心点加上法线偏移)
|
||||
const offsetDistance = 0.05;
|
||||
const targetPosition = targetZone.center.add(targetZone.normal.scale(offsetDistance));
|
||||
|
||||
// 计算旋转角度(根据法线方向)
|
||||
const targetDirection = targetZone.normal.scale(-1);
|
||||
const angle = Math.atan2(targetDirection.x, targetDirection.z);
|
||||
|
||||
console.log(`[自动排列] 目标区域 ${newIndex} 的位置:`, {
|
||||
center: targetZone.center,
|
||||
normal: targetZone.normal,
|
||||
targetPosition: targetPosition,
|
||||
rotation: angle * 180 / Math.PI
|
||||
});
|
||||
|
||||
// 移动模型到新位置
|
||||
const meshes = this.appModel.getCachedMeshes(model.modelId);
|
||||
if (meshes && meshes.length > 0) {
|
||||
const rootMesh = meshes[0];
|
||||
|
||||
// 更新位置
|
||||
rootMesh.position.copyFrom(targetPosition);
|
||||
|
||||
// 更新旋转
|
||||
rootMesh.rotation.y = angle;
|
||||
|
||||
console.log(`[自动排列] ✓ 模型 ${model.modelId} 已移动到索引 ${newIndex} 的位置`);
|
||||
} else {
|
||||
console.warn(`[自动排列] ✗ 找不到模型 ${model.modelId} 的网格`);
|
||||
}
|
||||
|
||||
// 更新映射(无论是否移动,都要确保映射正确)
|
||||
if (model.currentIndex !== newIndex) {
|
||||
const oldKey = `${wallName}[${model.currentIndex}]`;
|
||||
const newKey = `${wallName}[${newIndex}]`;
|
||||
this.zoneModelMap.delete(oldKey);
|
||||
this.zoneModelMap.set(newKey, model.modelId);
|
||||
console.log(`[自动排列] 更新映射: ${oldKey} -> ${newKey}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 禁用该墙面所有模型的拖拽功能
|
||||
console.log(`[自动排列] 开始禁用拖拽功能`);
|
||||
placedModels.forEach(model => {
|
||||
// 安全检查:确保 mainApp 和 appModelDrag 都存在
|
||||
if (this.mainApp && this.mainApp.appModelDrag && typeof this.mainApp.appModelDrag.setDragEnabled === 'function') {
|
||||
this.mainApp.appModelDrag.setDragEnabled(model.modelId, false);
|
||||
console.log(`[自动排列] ✓ 已禁用模型 ${model.modelId} 的拖拽功能`);
|
||||
} else {
|
||||
console.warn(`[自动排列] ✗ 无法禁用模型 ${model.modelId} 的拖拽功能:appModelDrag 未初始化`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`[自动排列] 墙面 ${wallName} 自动排列完成`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -29,8 +29,6 @@ export class AppEngin extends Monobehiver {
|
||||
this.object.setSize(window.innerWidth, window.innerHeight);
|
||||
this.object.setHardwareScalingLevel(1); // 1:1像素比例
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** 处理窗口大小变化 */
|
||||
|
||||
@ -306,6 +306,29 @@ export class AppModel extends Monobehiver {
|
||||
// 配置拖拽功能
|
||||
if (drag) {
|
||||
this.mainApp.appModelDrag?.configureDrag(modelName + '_' + modelId, drag);
|
||||
|
||||
// 检查该模型所在的墙面是否已满,如果满了则禁用拖拽
|
||||
if (this.mainApp.appDropZone) {
|
||||
// 从 zoneModelMap 中查找该模型所在的墙面
|
||||
let modelWallName: string | null = null;
|
||||
const fullModelId = modelName + '_' + modelId;
|
||||
|
||||
// 遍历 zoneModelMap 查找该模型
|
||||
this.mainApp.appDropZone['zoneModelMap']?.forEach((id: string, zoneKey: string) => {
|
||||
if (id === fullModelId) {
|
||||
const match = zoneKey.match(/^(.+)\[(\d+)\]$/);
|
||||
if (match) {
|
||||
modelWallName = match[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 如果找到墙面且墙面已满,禁用拖拽
|
||||
if (modelWallName && this.mainApp.appDropZone.isWallFull(modelWallName)) {
|
||||
console.log(`[拖拽控制] 墙面 ${modelWallName} 已满,禁用模型 ${fullModelId} 的拖拽`);
|
||||
this.mainApp.appModelDrag?.setDragEnabled(fullModelId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新 GameManager 的字典
|
||||
@ -507,6 +530,12 @@ export class AppModel extends Monobehiver {
|
||||
this.modelDic.Remove(modelName);
|
||||
this.modelMetadataDic.Remove(modelName);
|
||||
this.mainApp.gameManager?.updateDictionaries();
|
||||
|
||||
// 通知 AppDropZone 模型被删除
|
||||
if (this.mainApp.appDropZone && typeof this.mainApp.appDropZone.notifyModelRemoved === 'function') {
|
||||
this.mainApp.appDropZone.notifyModelRemoved(modelName);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@ -100,6 +100,8 @@ export class MainApp {
|
||||
this.appDropZone = new AppDropZone(this.appScene.object);
|
||||
// 设置模型管理器引用
|
||||
this.appDropZone.setModelManager(this.appModel);
|
||||
// 设置 MainApp 引用,以便访问 appModelDrag
|
||||
this.appDropZone.setMainApp(this);
|
||||
this.update();
|
||||
EventBridge.sceneReady({ scene: this.appScene.object });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user