web 版体验地址:http://106.55.55.247/genshin-maps/
apk 下载:qiuxiang.github.io/genshin-map…
目前已有的中文版原神地图无一例外的都用 leaflet 实现,而一些 app 提供的原神地图也无一例外的是套 webview,和我们平时用的地图 app 相比体验简直糟糕,主要问题在于:
- 移动、缩放后总是要等待 tilemap 加载,即便是在加载过,有缓存的情况下,加载仍然显得很慢。
- marker 在缩放时不同步移动,或者干脆不显示,这显然是因为大量 marker 同时做 transform 会导致严重的性能问题而做的回避。
- 显示大量 marker 的时候性能糟糕。
这些问题是 leaflet 本身就面临的,只要是基于 leaflet 做,体验都好不到哪里去。我们何不抛开 leaflet,重新思考怎么实现一个流畅的原神地图。游戏地图毕竟不同于现实世界的地图,数据量并没有那么大,完全可以塞入 app,由于数据量没有那么大,有些问题对也就不需要考虑了,实现起来并不会很复杂。
我们先思考上述 leaflet 的问题都是什么原因导致的,以及怎么解决。对于 tile 加载慢的问题,如果是 app 使用离线图片的情况下应该可以得到解决(其实并不能完全解决,后面详细说明),而对于 web,可以先把文件都加载并缓存在内存(同时关注内存消耗代价);而对于 marker 性能的问题原生 web 可能是无解的,leaflet 有两种实现方式,一种是基于 dom,显然,这个实现方式需要大量 dom 操作就是会有性能问题的。而另一种实现方式则是 canvas,用 canvas 理论上能获得很好的性能,但实现起来会复杂很多,而且实现的优劣对性能的影响非常大,看起来 leaflet 的 canvas 实现并不好,也许是没有能实现高效的渲染,也许是没有和手势识别很好的结合。
思考到这里,基本上可以确定,如果要实现体验更好的原神地图,使用 canvas 实现整个地图的绘制就是必须的,而且必须结合手势识别并实时渲染。
为什么选择 flutter
可能很多人并不了解 flutter web,在我看来其存在的意义并不只是顺便把 flutter app 编译成 web 这么简单而已。而可以作为一种新的开发 web app 的技术来使用,比如这里我用来实现原神地图的渲染。
flutter web 有两种渲染模式,这里我们只讨论性能最好的 canvaskit。在 canvaskit 模式下整个 app 都绘制在一个 canvas 里,相当于把原生渲染搬到了 web,在完全抛弃 dom 且有 skia 加成的情况下,flutter web 的上限要远高于传统 web。
虽然 flutter web 有性能上的优势,但劣势也非常明显,一个很明显的劣势就是首次需要加载的资源过多,其中至少需要 500k 的 js 和 3MB 的 canvaskit。如果用到了中文,还需要渲染时加载中文字体,这将导致首次渲染时中文字体不显示,并且加载字体时还会导致界面掉帧。
除了性能,兼容性和跨平台自然也是需要考虑的,就目前还没有人开发原神地图 app 的情况下,app 需要优先考虑,这里对 web 的讨论更多是对性能分析并验证。flutter 在渲染引擎跨平台方面有绝对的优势,不管哪个平台都可以无差别的渲染。