下载 App

如何让分享链接的访问者能看到/使用创作者保存的地图

05/034 浏览
你的分析方向是对的,但可以更精确地拆解。让我逐层回答。为什么 UI 一样,但数据不一样?这两者本质不同:内容来源特性左侧栏地形列表、工具栏按钮代码(Lua 脚本)打包在构建产物里,所有环境完全一致已保存的地图列表数据(运行时读取存储)取决于存储后端,不同环境/会话各自独立编辑器 UI 看起来一样,是因为它由同一份打包部署的代码渲染。而"加载地图"弹窗里的列表内容,是运行时从存储层读取的——这才是差异所在。你的分析是否正确?核心判断 “clientCloud 在 WASM 多人模式下为 nil,导致云端读写都断了” ——这个需要先验证。不过即使 clientCloud 可用,还有一个更基本的问题:clientCloud 是按用户隔离的。 你在本地预览时的用户身份,和通过分享链接访问时的用户身份,很可能不是同一个 uid。即使 clientCloud 正常工作,A 用户保存的数据,B 用户(或匿名访问者)也读不到。所以实际上有两层原因叠加:
  1. 存储后端可能不可用(clientCloud = nil)
  2. 即使可用,数据也按 uid 隔离(不同用户看不到彼此的存档)
→ serverCloud 中转是合理方案,按 uid 隔离存取即可。需求 B:让分享链接的访问者能看到/使用创作者保存的地图
→ 这不是 uid 隔离存储能解决的。你需要的是共享数据,比如:
  • 把地图存到一个公共 key(不按 uid 隔离)
  • 或者在构建时把地图 JSON 打包进资源目录(静态数据)
  • 或者用 serverCloud.message 做"发布"机制
  1. 先确认 multiplayer 是否 enabled,以及 WASM 环境下 clientCloud 和 serverCloud 的实际可用性
  2. 明确分享场景的数据共享需求(共享 vs 隔离)
  3. 再决定走 serverCloud 中转还是其他方案
既然地图是所有玩家共用的游戏内容,而不是每个玩家各自的存档,那性质就变了:这是"游戏关卡数据",不是"用户存档"数据类型例子存储方式游戏内容(所有人一样)关卡地图、NPC 配置打包进构建产物用户存档(每人不同)进度、背包、分数clientCloud / serverCloud你的地图属于前者。它不应该走 clientCloud 或 serverCloud,而应该作为静态资源打包进游戏。最简单的方案你在编辑器里做好地图 → 导出的 JSON 文件放进 assets/ 或 scripts/ 目录 → 构建时自动打包 → 所有玩家加载的都是同一份数据。流程:
创作者在编辑器制作地图
        ↓
保存为 maps/xxx.json(本地文件)
        ↓
文件已经在项目目录里了
        ↓
构建打包(build)
        ↓
所有玩家通过 cache/File 读取同一份 JSON
        ↓
所有人看到同一张地图
回到你的问题分享链接看不到地图,根本原因不是 clientCloud 的问题,而是:地图数据只存在于运行时存储(File API / clientCloud),没有进入构建产物。编辑器保存的 maps/xxx.json 是运行时通过 File API 写入的临时文件,它只存在于那一次会话的沙箱里。构建打包时,这个文件并不在 assets/ 或 scripts/ 目录中,所以不会被打包。分享链接打开的是一个全新的 WASM 实例,自然什么都没有。你需要做的把编辑器的"保存"产出(地图 JSON)拿出来放到项目的资源目录,然后重新 build。这样地图就成了游戏的一部分,所有环境、所有玩家都能访问到。至于 serverCloud 中转方案——它适合的场景是"玩家 UGC"(比如每个玩家创建自己的关卡并分享给别人)。如果你的需求只是"开发者做好一张地图,所有人玩",那根本不需要云端,静态打包就够了。
编辑器在浏览器(WASM)里运行时,File API 写入的是沙箱虚拟文件系统,不是项目源码目录。所以"保存"产出的 JSON 文件在那次会话结束后就消失了,也不会进入构建产物。设计方案:增加"导出"按钮在现有工具栏(保存、加载旁边)加一个 “导出” 按钮:┌────────────────────────────────────────────────┐
│ B画笔  撤销  重做  网格  保存  加载  导出  清空  │
└────────────────────────────────────────────────┘
                                    ↑ 新增
"导出"按钮的行为点击后,将当前地图的完整 JSON 复制到系统剪贴板。完整工作流创作者在编辑器中制作地图
        ↓
用"保存"做会话内暂存(和现在一样)
        ↓
满意后点"导出"
        ↓
地图 JSON 复制到剪贴板,界面提示"已复制"
        ↓
粘贴给 AI 助手,说"把这个地图存到项目里"
        ↓
AI 写入 scripts/data/default_map.json
        ↓
rebuild
        ↓
所有玩家(包括分享链接)加载的都是这份地图
游戏加载侧的变化游戏启动
    ↓
检查 scripts/data/default_map.json 是否存在
    ├── 存在 → 直接加载,作为默认地图
    └── 不存在 → 空地图 / 提示无地图
现有的"保存/加载"功能不需要改,它们继续负责编辑过程中的临时存档。“导出"是额外的一步,专门用于"定稿发布”。为什么选剪贴板而不是其他方式方案优缺点剪贴板复制最简单,一行 API 调用;用户粘贴给 AI 即可写入项目打印到控制台/日志大地图 JSON 可能几千行,日志里不好找弹窗显示文本框需要额外 UI,且大数据量时体验差自动写入项目目录WASM 沙箱做不到,运行时无法写源码目录你需要确认的问题
  1. 地图 JSON 大概多大? 你那张 112×84 的地图,序列化后大约多少 KB?如果超过剪贴板合理范围(比如 >500KB),可能需要考虑压缩或分块。
  2. 是否需要"导入"按钮? 即从剪贴板粘贴 JSON 加载地图。这样可以在不同会话间通过复制粘贴传递地图,不依赖云端。
  3. default_map.json 放在哪里? 建议 scripts/data/default_map.json,和代码放一起,构建时自动打包。你有偏好吗?
生成正面、背面、侧面,可以走动的角色形象截图
生成正面、背面、侧面,可以走动的角色形象
当前 NPC 角色编辑器的数据结构 编辑器使用 32×32 像素画布,数据结构大致是: 3 个朝向:正面、背面、侧面 2 个动画状态:静止(idle)、行走(walk) 每个状态可以有多帧,支持帧率控制 每帧本质上是一个 32×32 的颜色数组 要解决的 3 个问题 步骤 问题 方案 1. 图片→编辑器 128×128 PNG 导入为 32×32 像素数据 加载图片后逐像素采样(每4×4取1像素)
1 赞
9 回复
地图编辑器仿真 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 赞
【日常更新】支持2人、3人、4人对战截图
【日常更新】支持2人、3人、4人对战
优化了排行榜显示玩家昵称
3 赞
编辑器实体 zIndex 层级
问题 编辑器中墙段被房间面板覆盖不可见。原因:给房间设 zIndex=1 会创建 stacking context,其内部带背景色/TiledImage 的 floorLayer 作为 paint layer 在合成时盖过了同层级 zIndex=2 的墙段——差距太小不够可靠。 解决:底层不设 zIndex,上层用明显间距 错误做法(zIndex 间距太小 + 给底层也设 zIndex): --
官方
1 赞
碰撞方案
核心教训 1. 格子像素必须匹配精灵尺寸 5px格子+36px精灵=7.2:1比例,任何碰撞方案(AABB/空气墙/单点/格中心)都无法同时满足"不穿墙+四面间距一致+不跳格"。对齐环世界32px后,36px精灵≈1.1格,问题根本解决。 2. 连续渲染 + 格级碰撞的分层设计 渲染用连续坐标 x*S-18(平滑不跳),碰撞用格级检测(不穿墙),二者解耦。 3. 精灵大于格子时,单点检测必然不对称
官方
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 赞
以鼠标为锚点缩放
核心数学原理 缩放前后,鼠标指向的那个世界坐标点必须保持在同一屏幕位置。 已知:旧缩放 oldZoom、新缩放 newZoom、鼠标锚点屏幕坐标 (ax, ay)、当前偏移 (panX, panY) 步骤1:算出旧缩放下鼠标指向的世界坐标 wx = (ax - panX) / oldZoom wy = (ay - panY) / oldZoom 步骤2:新缩放后反解新偏移,让 wx/wy
官方
1 赞
围墙空气墙
问题根源 原系统用单点碰撞(Round(nx), Round(ny) 只检测中心1个点),角色精灵 36px(7.2格) 宽,中心停在 x=0.5 时精灵左半完全覆盖 5px 围墙,视觉"穿墙"。 1. AABB 矩形碰撞检测 — scripts/小人/导航.lua -- 角色碰撞体尺寸(格):脚底占据的地面矩形 -- 半宽 0.5 格(2.5px),半高 0.3 格(1.5px) local A
官方
1 赞
右键拖拽平移
一、问题本质 不是平移公式写错,而是 UrhoX UI 库指针事件派发的两个不对称陷阱叠加: 陷阱 现象 根因文件 OnPointerMove 不向父冒泡 右键按下 isPanning_=true,但 move 事件永远到不了 mapView urhox-libs/UI/Core/Widget.lua(OnPointerDown/Up 有 parent 冒泡,OnPointerMove 没有) H
官方
4 赞