hy-farm/docs/godot-map-pan-review.md
2026-05-29 19:54:56 +08:00

7.0 KiB
Raw Blame History

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,避免只体现缩放而遗漏拖动视口职责。

当前实现

地图边界

地图范围使用常量:

const MAP_PREVIEW_SIZE := Vector2(2000.0, 2000.0)

拖动偏移由 _clamped_scene_offset() 限制:

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. GroundHouseDogHouseFenceBackGameViewFenceFrontPetLayer 移到 FarmSceneRoot
  2. GameView 下严格匹配 Land + 数字的节点计算土地包围盒。
  3. 将土地包围盒中心平移到 2000x2000 地图中心。
  4. 将镜头偏移设为地图中心对准屏幕中心。

当前顺序是安全的:计算土地包围盒发生在 LandHitLayerLandLight 等运行时节点创建前,因此不会把命中层误算进土地范围。

拖动与点击冲突

当前使用 PAN_DRAG_THRESHOLD = 8 像素区分点击和拖动。

  • 移动距离小于阈值:仍按点击处理。
  • 移动距离达到阈值:进入地图拖动。
  • 拖动开始时调用 FarmInteractionCoordinator.on_scene_pan_started()
  • 拖动结束后调用 on_scene_pan_finished(),延迟清理抑制标记。

土地点击被抑制的路径:

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

已执行验证

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

浏览器验证目标:

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 改为真实大图或分块贴图,避免拉伸纹理。