下载 App

等距视角下的经典问题:点击树却删不掉

05/083 浏览综合
这是一个等距视角下的经典问题——树的图像从根部向上延伸,点击树冠时光标实际映射到了不同的网格单元格。让我分析代码找到根因。
关键发现!看 _RenderOneTree 的渲染逻辑:
nvgRect(nvg, -drawW * 0.5, -drawH, drawW, drawH)
树的图像是从中心点向上延伸的(-drawH),这意味着树的视觉位置远高于其网格单元。当用户点击树冠时,光标映射到的网格行可能是好几行以前的位置。
现在看看鼠标坐标到网格行列的转换逻辑。
现在我理解了完整的流程。问题的根因是:
树渲染:树的图像从网格单元中心向上绘制(y 从 -drawH 到 0),所以树冠在等距空间中位于实际行的上方
ScreenToCell:点击树冠时,经过反向等距变换后映射到的行号比树实际所在行更小(更靠"远处")
因此用户点击树冠擦除的是错误的单元格
最佳方案:当资源橡皮擦模式下,不仅检查光标所在格,还要向下(更大行号)搜索附近几行是否有资源树的视觉覆盖了当前点击位置。让我看看具体的树高在内容坐标系中跨了多少行。
TILE_SIZE=64。树的 drawH = 256 * 0.75 = 192,也就是大约 192/64 = 3 行高度。再加上等距压缩(isoScaleY),树冠在屏幕空间会覆盖更多行。
最合理的修复方式是:在资源橡皮擦模式下,不是只擦光标所在的格子,而是向下搜索若干行,找到第一个有资源树的格子并擦除它。这样用户点击树冠就能正确定位到树根所在的格子。
现在来看看在 _ApplyBrush 中资源橡皮擦路径下如何修复。问题是当 selectedResourceId_ == EMPTY_RESOURCE_ID(橡皮擦模式),用户点击的是树冠,但 ScreenToCell 返回的 row 在树根实际行之前(上方)。
修复方案:在资源橡皮擦模式下,如果当前格子没有资源,向下搜索几行(树高范围内),找到最近的有资源的格子来擦除。
好,旋转角 = π/4 (45°),isoScaleY = 0.5。
树渲染使用 nvgRotate(-rotation_) + nvgScale(1, 1/isoScaleY_) 来抵消全局等距变换,使树直立显示。当用户点击树冠,经反向等距变换后,屏幕上的"向上"方向映射到内容空间中同时减小 row 和 col。
最实用的方案是:在资源橡皮擦模式下,如果当前格子没有资源,向附近搜索(优先向 row+/col+ 方向)找到被点击树冠对应的树根格子。
现在实现修复。当橡皮擦模式下,当前格子无资源时,搜索附近可能被点到的树。树在屏幕上直立,经过 45° 旋转和 0.5 压缩后,"屏幕上方"在内容空间中约对应 row-n, col-n 的方向。所以树根在点击位置的 row+/col+ 方向。
参数确认:width=256, height=256, scale=0.75 → drawW=drawH=192。TILE_SIZE=64。
现在实现 _FindTreeRootForEraser 方法。核心思路是对点击位置附近的资源格子做精确的屏幕空间碰撞检测,找到视觉上被点击到的那棵树。
构建成功。修复已完成。
问题原因:在等距视角(45° 旋转 + 0.5 Y 压缩)下,树的图像从格子中心向屏幕上方延伸(树冠在上方)。当用户点击树冠时,ScreenToCell 经过逆等距变换后,返回的 row/col 比树根实际所在格子更小,导致擦除操作指向了空格子。
修复方案:在 _ApplyBrush 中,当橡皮擦模式下点击的格子没有资源时,调用新增的 _FindTreeRootForEraser 方法。该方法通过屏幕空间碰撞检测搜索附近的资源格子:
对搜索范围内每个有资源的格子,计算点击位置相对于该格子的内容空间偏移
将偏移转换回屏幕空间(正向等距变换:旋转 → Y 压缩)
检查屏幕空间偏移是否落在树的视觉包围盒内(X: ±drawW/2, Y: -drawH ~ 0)
多棵树命中时选择 screenDY 最接近 0 的(即视觉上距离树根最近、前景层的树)
现在你可以点击任意一棵树的任何部位(树冠、树干、树根)来擦除它。
生成正面、背面、侧面,可以走动的角色形象截图
生成正面、背面、侧面,可以走动的角色形象
当前 NPC 角色编辑器的数据结构 编辑器使用 32×32 像素画布,数据结构大致是: 3 个朝向:正面、背面、侧面 2 个动画状态:静止(idle)、行走(walk) 每个状态可以有多帧,支持帧率控制 每帧本质上是一个 32×32 的颜色数组 要解决的 3 个问题 步骤 问题 方案 1. 图片→编辑器 128×128 PNG 导入为 32×32 像素数据 加载图片后逐像素采样(每4×4取1像素)
1 赞
9 回复
【日常更新】支持2人、3人、4人对战截图
【日常更新】支持2人、3人、4人对战
优化了排行榜显示玩家昵称
3 赞
地图编辑器仿真 tick 重建抑制
UI 重建频率 = 事件分发的可靠性上限。 只要有一帧 SetRoot 销毁了正在处理 pointer 事件的控件,跨重建边界的 Down/Up 对就会被吞。高频仿真 tick 必须在 UI 边界按页面过滤。 关键代码(scripts/main.lua HandleUpdate) 四步走:先原地处理人员 → 聚合所有仿真 changed → 地图页强制压制 → 只放行显式/登录态变化。 -- ma
官方
4 赞
穿透层修复
经验一:CSS transform 穿透层修复模式 问题本质 当容器使用 CSS transform: translateX/Y/scale 平移/缩放子树时,即使父容器有 overflow = "hidden",引擎的命中检测可能不裁剪越界区域。如果 transform 后的子树有更高的 zIndex,它会在视觉范围外拦截其他兄弟节点的指针事件。 受影响的场景 地图编辑器(右键平移/滚轮缩放后)
官方
4 赞
以鼠标为锚点缩放
核心数学原理 缩放前后,鼠标指向的那个世界坐标点必须保持在同一屏幕位置。 已知:旧缩放 oldZoom、新缩放 newZoom、鼠标锚点屏幕坐标 (ax, ay)、当前偏移 (panX, panY) 步骤1:算出旧缩放下鼠标指向的世界坐标 wx = (ax - panX) / oldZoom wy = (ay - panY) / oldZoom 步骤2:新缩放后反解新偏移,让 wx/wy
官方
1 赞
编辑器实体 zIndex 层级
问题 编辑器中墙段被房间面板覆盖不可见。原因:给房间设 zIndex=1 会创建 stacking context,其内部带背景色/TiledImage 的 floorLayer 作为 paint layer 在合成时盖过了同层级 zIndex=2 的墙段——差距太小不够可靠。 解决:底层不设 zIndex,上层用明显间距 错误做法(zIndex 间距太小 + 给底层也设 zIndex): --
官方
1 赞
图片加载三层优化设计
目标场景:地图编辑器"物品/墙体/地面/房间/人员"调色板弹窗的图片首帧显示 文档目的:沉淀"图片为什么慢、怎么治、发布后玩家体验如何、未来加资源时 preload_groups 怎么取舍"的完整结论,避免重复踩坑。 一句话结论 WASM 下图片"慢"不是单一问题,而是下载 / 解码 / 上传 GPU 三件事全堆在"玩家点弹窗那一刻"做导致的。优化的本质是把这三件事提前到启动期做(让玩家点的时候图
官方
1 赞
右键拖拽平移
一、问题本质 不是平移公式写错,而是 UrhoX UI 库指针事件派发的两个不对称陷阱叠加: 陷阱 现象 根因文件 OnPointerMove 不向父冒泡 右键按下 isPanning_=true,但 move 事件永远到不了 mapView urhox-libs/UI/Core/Widget.lua(OnPointerDown/Up 有 parent 冒泡,OnPointerMove 没有) H
官方
4 赞
精灵平滑移动、墙碰撞体积
一、 渲染层用连续坐标(scripts/页面/校园地图.lua,三处统一): -- NPC 定位(第408-410行) local contLeft = (character.x or 0) * 5 - 18 - charLeft local contTop = (character.y or 0) * 5 - 36 - charTop -- 主角定位(第504-506行) local con
官方
1 赞
地面样式配置归一化
1. 唯一真相源 scripts/数据/地图/地面样式配置.lua local FloorStyleConfig = {} -- ★ 所有地面样式集中定义在这里 FloorStyleConfig.STYLES = { ["木地板"] = { texture = "image/地面/木地板_无缝.png", tileSize = 40 }, ["草地"] = { texture = "imag
官方
4 赞