来自 Command 的战报。星图是 X-Wars 的核心 - 但在手机上,它已经开始让人觉得像是在拖动一幅沉重的画,而不是穿越太空。今天,我将发布一个基于 WebGL(通过 PixiJS)的全新默认渲染器,让战争迷雾和占领区在缩小时依然可见,同时保留旧渲染路径作为紧急开关,直到新版本在生产环境中经过充分检验。
为什么星图感觉很慢
一张鲜活的星图并不是一幅静态图片。它是一台在不断扩张的世界上移动的相机:地块网格、探索迷雾、信标占领区色调、恒星、行星精灵、舰队标记、航行轨迹、扫描环和可达范围预览。在笔记本电脑上,旧方案通常看起来没什么问题。但在中端 Android 和 iOS 设备上,它会出现卡顿 - 尤其是在存在大型占领区或大片已探索区域时。平移和双指缩放都会显得迟滞。这不是内容本身的问题,而是渲染器带来的负担。
如何存储庞大的宇宙而不拖垮浏览器
宇宙是有意设计得如此庞大。指挥官不需要把每个地块都作为一行 JSON 下载下来。服务器和客户端通过稀疏结构协同工作 - 只处理你已经揭示、发现或当前视野所需的内容。
以位图存储探索迷雾
战争迷雾并不是一份列出每个黑暗地块的清单。已揭示空间存储在分块位图中 - 将宇宙中固定大小的方形区域压缩成比特位。一个 64 × 64 地块的区块只需几百字节。浏览器接收的是与你的地图边界相交的区块,而不是一部长篇坐标小说。当舰队侦察一片区域时,我们会设置相应的比特位并发送补丁。正因如此,即使经过数月探索,战争迷雾的存储成本依然很低。
将占领区存为覆盖区域,而不是墙纸地块
信标领土使用 Chebyshev 距离 - 即 dx 与 dy 绝对值的较大者 - 因此覆盖半径在地块网格上实际上就是一个与坐标轴对齐的正方形。不同等级会把这个正方形从小型巡逻范围扩展成巨大的宣称区域(边长可达数十个地块,最重型模块可接近 100 个地块)。游戏不需要把每个被占领的地块都存成独立文档。所有权会根据启用中的信标中心和半径重新构建,同时从宣称区域中挖去行星本体占据的地块。你自己的信标互相重叠时,仍会显示为一层统一色调,而不是叠成越来越深的多层颜色。
地图 API 实际发送的内容
一次地图加载得到的是一块图钉板,而不是整个宇宙的纹理图集:你已知的星系、你拥有或侦测到的舰队、覆盖范围与你的迷雾或侦察区域相交的信标、你发现的衰变残骸,以及足以容纳这些锚点的边界。探索区块会一并到达。随后,客户端会决定当前相机视野中需要绘制哪些内容。这种分工 - 在线路上传输稀疏的世界状态,仅为视口生成密集像素 - 是浏览器 MMO 星图在大规模运行时保持务实的唯一方式。
旧渲染器 - 坦诚的事后复盘
之前的星图是一个 React DOM 世界:一个巨大的图层通过 CSS translate 和 scale 移动,图钉由定位按钮和图像构成,战争迷雾与占领区则使用 SVG 矩形绘制。对于 alpha 阶段的首个版本来说,这是正确的选择 - 可交互、易调试、迭代迅速。但随着占领区和已探索迷雾不断扩大,它并没有很好地经受住时间考验。
- 用 CSS 缩放一个世界大小的图层,会迫使浏览器在每一帧平移时合成一棵巨大的节点树。
- 占领区会先在 JavaScript 中展开完整的 Chebyshev 覆盖区域,再为视口内的每个被占领地块绘制一个 SVG 矩形 - 结果正确,但代价高昂。
- 战争迷雾使用合并后的 SVG 矩形覆盖已加载画布 - 比每个地块一个节点更好,但随着揭示区域扩大,SVG 负担依然很重。
- 行星和舰队图钉都是真实的 DOM 元素,带有滤镜、圆环和点击区域 - 几十个时尚可接受,但在一个不断变换的父元素下达到数百个时,成本就很高。
- 过去在缩小时会完全移除战争迷雾和占领区,好让宏观视图得以运行 - 但这也隐藏了你在审视战区时最需要的情报。
新渲染器 - 使用 PixiJS 的 WebGL
星图现在通过 PixiJS 绘制到与视口同样大小的 canvas 上,由 PixiJS 与 WebGL 通信(并在需要时使用安全的回退路径)。世界不再是一张拥有数十亿像素的 DOM 巨幅画布,而是覆盖于 GPU 友好型绘制调用之上的相机矩阵。HUD 面板、对话框和指挥界面仍然使用 React - 只有鲜活的地图表面被迁移。
无需让 React 承受重负的相机
当你平移或双指缩放时,相机变换会立即更新 Pixi 舞台。React 仍会以更平缓的节奏获知焦点与剔除边界 - 采用量化后的焦点步进和手势结束事件 - 因此我们不必在手指每移动一个像素时都重建整个宇宙。移动中的舰队和航行轨迹位于动态层中,可以持续更新,而无需重新挂载恒星与战争迷雾。
缩小时依然有用的图层
细节层级依然存在,但它改变的是表现形式 - 而不是战争迷雾和占领区是否存在。放大时,你会看到地块网格、行星精灵和清晰的图钉。缩小时,你会看到更粗略的网格、恒星群和更简洁的标记 - 同时保留占领区方块与迷雾,使战略态势不会变成一片空白。
- 背景:网格、战争迷雾、占领区色调、范围轮廓(信标连接、舰队侦测、移动可达范围、扫描雷达)。
- 天体:恒星、行星、信标标记、残骸图钉。
- 动态内容:舰队标记、航行路径、航行计划预览、合并箭头。
为什么 Chebyshev 覆盖区域对绘制很重要
由于 Chebyshev 覆盖区域是正方形,占领区可以按每个信标绘制一个四边形,而不必绘制数千个地块矩形。战争迷雾仍使用合并后的已揭示区域,但只处理视口实际需要的部分。这就是铺满墙纸与直接盖章之间的区别。
作为指挥官,你应该注意到什么
- 手机上的平移和双指缩放更加流畅,尤其是在被占领或充分探索的空间中。
- 缩小视图规划下一条走廊时,战争迷雾和占领区依然清晰可读。
- 所选舰队的侦测范围和信标覆盖预览会以清晰的方形绘制在地图上。
- 游戏规则保持不变 - 这只是渲染器变更,并非对战争迷雾、信标或舰队的重新设计。
紧急开关与对 alpha 阶段的坦诚
Pixi 是默认方案。如果上线后出现问题,我可以直接把线上默认设置切回旧版 DOM 路径,而无需完整重新构建。已经打开的地图标签页会继续使用当前渲染器,直到你重新加载。我有意在短暂的观察期内保留旧路径 - 大约一周的真实游玩时间 - 等我确认可以信任这块新玻璃后,就会将其移除。
如果刷新后,地图在某款特定设备上仍然卡顿,请通过 Command Relay 告诉我,并提供设备、浏览器,以及你当时查看的大致位置。目标很简单:让星图重新拥有太空应有的感觉 - 指尖下轻盈流畅、情报丰富,并为前方仍在等待的战斗做好准备。- Command
