易恺铭
EN

一份 TypeScript 逻辑,喂给 UE、Node 后端和 Web 前端

约 2 分钟

今年做的事情里,我现在认为最有价值的一件,是用 TypeScript 统一了基础的地理数据管理结构。

地形光影、区域划分、道路生成,这些算法原本都长在 Cocos Creator 的工程里,依赖它的库。我把它们逐步改写成不依赖任何引擎的基础 TypeScript 逻辑。

当时做这件事的动机很朴素:不想在换引擎的时候重写一遍。做完之后才发现,它换来的东西比”不用重写”多得多。

剥出 hcommon

这个月把这层正式剥了出来,叫 hcommon。

它是一层纯计算:不碰任何引擎 API,不碰渲染,不碰文件系统。做成 git submodule,由 UE 前端、node 后端、web 前端三方引用。

submodule 这套流程我以前没认真用过,最关键的一条命令是:

git submodule update --remote

它从上游拉最新,而不是停在父仓库记录的那个 commit 上。三个仓库同时在改 hcommon 的时候,这条命令是同步的入口。

三端各自负责什么

node 后端     服务端:重活、可缓存的计算
UE 前端       交互端:真正在里面走动的那一端
web 前端      全局 visualizer:从外面看整个世界

这次最大的结构调整,是把地形数据纹理的计算 —— AO、阴影、功能区域、道路、建筑物 —— 整体移动到 backend,算完及时 cache。

两个收益:

一是解放出每次生成都要重算的时间。这些数据对同一个地点是稳定的,本来就不该每次进场景重算一遍。

二是 chunk 逻辑被简化了。客户端不再需要知道这些数据是怎么来的,只需要知道去哪儿取。抽象层的位置一旦挪对,上层代码会自己变短。

可视化带来的意外收益

做了一个很简单的协议:定时把 UE 里的经纬度坐标同步给服务器,然后在 web 前端展示出来。跳变用最简单的 lerp 解决,后续再考虑用航位推算法模拟真实行走。

这个东西本来只是想”看见自己在哪儿”。

结果做完之后,很快定位到了一批之前根本看不见的问题:UE 这边的高程、坐标、区域数据同步整体修了一遍,然后把修好的数据应用到了植被分布上。

所以可视化的价值不在好看。它把两端的数据摆在同一张图上,不一致会自己跳出来。 之前这些错误不是没发生,是没人能发现它发生了。

代价

两条,都很实在。

RHI 抽象只能表达两边都有的东西。 为了让同一套高层逻辑同时跑在 UE5 和 Cocos Creator 上,某些功能不得不作出妥协。这是抽象的固有成本,不是实现问题。

puerts 在线程里调用是不安全的。 这是 11 月底撞到的。它直接决定了分工的边界:和生成相关的、需要在工作线程上跑的数据,必须放在 C++ 这边;TypeScript 留给和服务器打交道的那些 api 调用。

现在的边界

这套东西证明了”纯计算层可以跨端复用”,但它还没有经受住性能压力。

真正重的生成仍然在 C++ 里。TypeScript 这层负责的是流程和数据编排,不是热路径。如果哪天需要把热路径也放进来,这个架构要重新论证一次。

下一步的两件事:把道路生成为 spline road;把路网分析出来,让道路能升级成高架桥、立交桥和多车道。

评论