下载 App

树和树重叠时,注意层叠显示关系

05/081 浏览
现在我清楚了完整的修复方案。让我实施:
问题 1(排斥区失效):SpawnInitialTrees 在建筑从云端同步之前调用,此时 mapData.buildings 为空。需要在云端同步后清除冲突的树。
问题 2(深度排序):树和建筑分别在两个渲染步骤绘制(建筑先、NPC 后),树总是覆盖在建筑上面。需要让树也参考建筑的行位置来决定遮挡关系。
建筑 9 格排斥区 — BUILDING_BUFFER = 3,建筑周围向外扩展 3 格(含建筑本身约 9 格范围),树木不会再生成在建筑上
树木深度排序 — _SyncNPCEntries() 中按行号升序排列树木,行号小的(远处)先绘制,行号大的(近处)后绘制覆盖在上面,解决了"树上长树"的视觉错误
关键发现:建筑在步骤 4 渲染,NPC(包括树)在步骤 4.05 渲染。这意味着所有 NPC/树都画在建筑之后(上面)。让我看渲染建筑的方法和整体渲染顺序。
现在我理解了全部问题:
渲染顺序问题:建筑在步骤 4 渲染,NPC/树在步骤 4.05 渲染,所以树总是画在建筑上面。建筑绘制用的是 中心锚点 (cx, cy = center),而树作为 NPC 用的是 底部锚点。
排斥区问题:需要确认排斥逻辑是否在初始化时正确获取了 buildings 数据。
让我检查初始化时 buildings 是否已经存在。
找到关键问题了!建筑数据是从云端异步加载的(WallClient.buildingData),在 SpawnInitialTrees(15) 调用时,云端建筑可能还没同步到 mapData.buildings 中。树先于建筑数据生成了,所以排斥检查时 buildings 列表可能是空的。
让我看看云端建筑重建发生在什么时候。
确认了。建筑重建是在 WallClient.SetOnSync 回调(即 rebuildFromCloud())中发生的,这是一个异步事件。而 SpawnInitialTrees(15) 是在 mapData 初始化后立即调用的,此时云端建筑数据尚未到达,mapData.buildings 是空的。
解决方案:
排斥区问题:将树的初始生成延迟到云端建筑同步完成之后,或者在同步完成后重新清理与建筑冲突的树
深度排序问题:树不应该作为独立的 NPC 层绘制在所有建筑之上,需要按行号与建筑混合排序
让我来实现修复。
现在来实施完整修复。需要:
TreeSystem 增加 PurgeConflicting() 方法:在云端建筑同步后,移除与建筑排斥区冲突的树
深度排序:树需要在 _RenderBuildings 中按行混合渲染,而不是作为 NPC 独立渲染。最简方案是把树的渲染也放到 _RenderBuildings 中按行号排序。
但修改 MapCanvas.lua 涉及较多改动且该文件已超 4000 行。更好的方案是:在 _RenderNPCs 中,对标记为 _isTree 的条目,检查是否应该被建筑遮挡(即树的行 < 建筑的行底部时,树应该在建筑后面 —— 但因为渲染顺序固定,树总在建筑上面)。
最实际的方案:把建筑也加入 NPC 列表,统一按行排序渲染。这样建筑和树可以按行号交错绘制。但这改动太大。
另一个方案:在 MapCanvas 的主渲染流程中,将建筑和 NPC 合并到一个列表里统一按行排序渲染。让我看看能否在渲染时处理。
实际上最简单有效的方案是:把树从 NPC 列表移出来,改为直接注入到 MapCanvas 的建筑渲染循环中,让建筑和树按行号混合排序绘制。
让我重新审视渲染架构,找到最小改动方案。
最小改动方案:将步骤 4(建筑)和步骤 4.05(NPC)合并成一个按行排序的混合渲染步骤。修改 _RenderBuildings 使其同时处理建筑和树,按行号排序混合渲染。
但这会让 _RenderBuildings 改动较大。更优的方案是:新建一个 _RenderBuildingsAndTrees 方法,替代原来的两步渲染。
不过再想一下,实际上最小改动方案是:
在 _RenderNPCs 中,先渲染行号小于建筑的树,然后由 _RenderBuildings 渲染建筑,然后再渲染行号大于建筑的树… 这太复杂了。
最实用的方案:在步骤 4 和 4.05 之间不再分开,而是合并到一个方法中按行号统一排序渲染建筑和 NPC。
让我实现这个方案。
构建成功。以下是本次修复的完整总结:
修复了两个问题:
建筑排斥区失效 — 根因是 SpawnInitialTrees() 在地图创建时立即执行,而此时建筑数据尚未从云端同步到达,mapData.buildings 为空,排斥检查形同虚设。
修复:在 main.lua 的 rebuildFromCloud() 末尾调用 treeSystem_:PurgeConflicting(),云同步完成后立刻清除所有与建筑冲突的树木。
树木与建筑深度排序错误 — 原来建筑在 step 4 渲染,树木在 step 4.05 渲染,导致树木永远画在建筑上方。
修复:重写 _RenderBuildings,将建筑和树木收集到同一列表中,按行号(建筑用底边行、树用所在行)升序排序后统一绘制。树木在 _RenderNPCs 中被跳过,避免重复渲染。
你可以预览测试一下,看看树木是否正确避开了建筑区域,以及前后遮挡关系是否正确。
生成正面、背面、侧面,可以走动的角色形象截图
生成正面、背面、侧面,可以走动的角色形象
当前 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 赞
编辑器实体 zIndex 层级
问题 编辑器中墙段被房间面板覆盖不可见。原因:给房间设 zIndex=1 会创建 stacking context,其内部带背景色/TiledImage 的 floorLayer 作为 paint layer 在合成时盖过了同层级 zIndex=2 的墙段——差距太小不够可靠。 解决:底层不设 zIndex,上层用明显间距 错误做法(zIndex 间距太小 + 给底层也设 zIndex): --
官方
1 赞
以鼠标为锚点缩放
核心数学原理 缩放前后,鼠标指向的那个世界坐标点必须保持在同一屏幕位置。 已知:旧缩放 oldZoom、新缩放 newZoom、鼠标锚点屏幕坐标 (ax, ay)、当前偏移 (panX, panY) 步骤1:算出旧缩放下鼠标指向的世界坐标 wx = (ax - panX) / oldZoom wy = (ay - panY) / oldZoom 步骤2:新缩放后反解新偏移,让 wx/wy
官方
1 赞
精灵平滑移动、墙碰撞体积
一、 渲染层用连续坐标(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. 格子像素必须匹配精灵尺寸 5px格子+36px精灵=7.2:1比例,任何碰撞方案(AABB/空气墙/单点/格中心)都无法同时满足"不穿墙+四面间距一致+不跳格"。对齐环世界32px后,36px精灵≈1.1格,问题根本解决。 2. 连续渲染 + 格级碰撞的分层设计 渲染用连续坐标 x*S-18(平滑不跳),碰撞用格级检测(不穿墙),二者解耦。 3. 精灵大于格子时,单点检测必然不对称
官方
1 赞
右键拖拽平移
一、问题本质 不是平移公式写错,而是 UrhoX UI 库指针事件派发的两个不对称陷阱叠加: 陷阱 现象 根因文件 OnPointerMove 不向父冒泡 右键按下 isPanning_=true,但 move 事件永远到不了 mapView urhox-libs/UI/Core/Widget.lua(OnPointerDown/Up 有 parent 冒泡,OnPointerMove 没有) H
官方
4 赞
自动寻路赠送
核心功能 携带模式(点击物品跟鼠标)下: ≤8格:点击小人直接赠送(金色边框) >8格:点击远距离小人 → 自动寻路走向目标 → 到达8格内自动赠送 取消:玩家按方向键/WASD/摇杆手动移动 → 立即取消,恢复物品 关键经验(3条踩坑教训) 经验1:类型标识不是中文,是英文枚举值 地图编辑器放置的角色 type/job 字段是英文标识(teacher_3、doctor、cleaner_2、tea
官方
1 赞