# Godot 农场地图拖动功能检验 日期:2026-05-12 ## 范围 本轮检验对象是 Godot 主农场的地图拖动预览能力: - 地图可拖动范围最大为 `2000x2000`。 - 默认进入农场时,土地内容位于地图中心。 - 背景图不足时先使用现有背景拉伸铺底,不额外补图。 - 拖动地图不能误触土地菜单、扩建弹窗或长按提示。 - 缩放、建筑点击、扩建入口和固定 HUD 不能被拖动能力破坏。 ## 模块拆分结论 该功能已经按现有架构拆出,主逻辑没有堆回 `game_scene.gd`。 | 模块 | 职责 | 当前判断 | | --- | --- | --- | | `scripts/ui/farm/farm_viewport_controller.gd` | 农场内容根节点、`2000x2000` 地图、默认居中、单指/鼠标拖动、双指/Ctrl 滚轮缩放、边界 clamp | 拖动功能核心已独立 | | `scripts/ui/farm/farm_interaction_coordinator.gd` | 土地点击、长按、菜单、背包;只通过 `on_scene_pan_started/finished` 抑制拖动误触 | 和地图拖动保持低耦合 | | `scripts/ui/game_scene_runtime_assembler.gd` | 创建缩放控制器和土地交互模块,并连接拖动开始/结束回调 | 只做装配 | | `scripts/ui/game_scene.gd` | 当前只保留扩建图标透明命中区的坐标同步 | 仍有一个可继续迁出的 UI 坐标桥接点 | 控制器已命名为 `FarmViewportController`,避免只体现缩放而遗漏拖动视口职责。 ## 当前实现 ### 地图边界 地图范围使用常量: ```gdscript const MAP_PREVIEW_SIZE := Vector2(2000.0, 2000.0) ``` 拖动偏移由 `_clamped_scene_offset()` 限制: ```gdscript var scaled_map_size := MAP_PREVIEW_SIZE * _zoom var min_offset := _panel_size - scaled_map_size clampf(value.x, minf(min_offset.x, 0.0), 0.0) clampf(value.y, minf(min_offset.y, 0.0), 0.0) ``` 以当前屏幕 `640x960` 为例: | 缩放 | 缩放后地图 | X 偏移范围 | Y 偏移范围 | 结论 | | --- | --- | --- | --- | --- | | `0.6667` | 约 `1333x1333` | `[-693, 0]` | `[-373, 0]` | 缩小时仍有可预览区域,不露出黑边 | | `1.0` | `2000x2000` | `[-1360, 0]` | `[-1040, 0]` | 满足 2000 地图拖动 | | `1.3` | `2600x2600` | `[-1960, 0]` | `[-1640, 0]` | 放大后边界随缩放扩大 | 边界设计合理:偏移范围以“缩放后的地图尺寸 - 屏幕尺寸”为准,缩放和拖动共用同一套 clamp,不会在缩放后越界。 ### 默认居中 默认进入时执行: 1. 把 `Ground`、`House`、`DogHouse`、`FenceBack`、`GameView`、`FenceFront`、`PetLayer` 移到 `FarmSceneRoot`。 2. 从 `GameView` 下严格匹配 `Land` + 数字的节点计算土地包围盒。 3. 将土地包围盒中心平移到 `2000x2000` 地图中心。 4. 将镜头偏移设为地图中心对准屏幕中心。 当前顺序是安全的:计算土地包围盒发生在 `LandHitLayer`、`LandLight` 等运行时节点创建前,因此不会把命中层误算进土地范围。 ### 拖动与点击冲突 当前使用 `PAN_DRAG_THRESHOLD = 8` 像素区分点击和拖动。 - 移动距离小于阈值:仍按点击处理。 - 移动距离达到阈值:进入地图拖动。 - 拖动开始时调用 `FarmInteractionCoordinator.on_scene_pan_started()`。 - 拖动结束后调用 `on_scene_pan_finished()`,延迟清理抑制标记。 土地点击被抑制的路径: ```text FarmViewportController pan started -> FarmInteractionCoordinator.on_scene_pan_started() -> stop long press timer -> suppress next land press -> hide selection UI ``` 该设计能避免“拖动土地后弹出土地菜单或扩建弹窗”的误触。 ### 固定 UI 与农场内容分离 只迁移农场内容到 `FarmSceneRoot`,顶部 HUD、左侧按钮、底部世界/家园按钮仍留在主场景固定层。因此拖动地图不会带动 HUD。 ### 背景策略 当前使用 `FarmZoomBackdrop` 将原背景拉伸到 `2000x2000`,并隐藏原 `Ground`。这符合“背景图不够先不用管”的要求。后续补齐大地图背景时,只需要替换 `FarmZoomBackdrop` 的纹理来源,不需要重写拖动逻辑。 ## 功能检验结果 | 检验项 | 结果 | | --- | --- | | 默认土地在视野中心 | 通过 | | 鼠标拖动地图可移动视野 | 通过 | | 拖动后不弹扩建面板 | 通过 | | 拖动后不弹土地菜单 | 通过 | | HUD 不随地图拖动 | 通过 | | Web 导出后可运行 | 通过 | | smoke 主流程 | 通过 | 截图记录: - `docs/ui-baseline/godot-map-pan-final-default.png` - `docs/ui-baseline/godot-map-pan-final-after-drag.png` - `docs/ui-baseline/godot-map-pan-rename-default.png` - `docs/ui-baseline/godot-map-pan-rename-after-drag.png` ## 已执行验证 ```sh godot --headless --path godot/FarmGodot --check-only --script res://scripts/ui/farm/farm_viewport_controller.gd godot --headless --path godot/FarmGodot --check-only --script res://scripts/ui/farm/farm_interaction_coordinator.gd godot --headless --path godot/FarmGodot --check-only --script res://scripts/ui/game_scene_runtime_assembler.gd godot --headless --path godot/FarmGodot --check-only --script res://scripts/ui/game_scene.gd godot --headless --path godot/FarmGodot --script res://tools/verify_p0.gd godot --headless --path godot/FarmGodot --import --quit godot --headless --path godot/FarmGodot --export-release Web build/web/index.html npm run smoke:godot:web ``` 浏览器验证目标: ```text http://127.0.0.1:8792/index.html ``` ## 边界风险 | 风险 | 当前影响 | 建议 | | --- | --- | --- | | `2000x2000` 固定在控制器常量里 | 后续如果不同地图皮肤尺寸不同,需要改代码 | 改成从 `game_scene_runtime_assembler.gd` 的 constants 注入 | | 建筑直接命中仍是按点击入口处理 | 拖动从建筑区域开始时,后续可能需要更严格的 tap/release 判定 | 若出现误触,把农场建筑 direct hit 改为 release 后、且未超过拖动阈值才触发 | | 缩放没有围绕双指中心或鼠标位置缩放 | 当前可用,但放大时视角体验不够细 | 后续按手势中心调整 `_scene_offset` | | 没有惯性滑动和边界回弹 | 当前符合第一版预览需求 | 后续如果要接近原生手感,可加轻量 Tween,但要避免 `_process` 常驻计算 | ## 优化优先级 P0 暂无阻断问题。 P1: - 将地图尺寸从常量改为装配层配置,便于不同背景/地图皮肤切换。 - 把扩建图标命中区同步从 `game_scene.gd` 迁到 `SceneHitRouter` 或农场交互模块,进一步减薄主场景。 - 建筑 direct hit 改为 tap 语义,避免未来拖动从房屋/狗窝起手时误触面板。 已处理: - `FarmSceneZoomController` 已重命名为 `FarmViewportController`,文件同步改为 `farm_viewport_controller.gd`。 - 土地包围盒匹配已从 `Land*` 改为 `Land` + 数字,避免 `LandPreview*` 这类装饰节点被纳入默认居中计算。 P2: - 增加缩放中心保持逻辑,让双指缩放时手指中点下的地图内容保持稳定。 - 增加可选惯性拖动和边界阻尼。 - 背景素材补齐后,把 `FarmZoomBackdrop` 改为真实大图或分块贴图,避免拉伸纹理。