我把《塞尔达传说》搬上苹果设备,「独占」还剩什么?

52 个小时,两天多一点,不到三天。
我把 Switch 版《塞尔达传说:旷野之息》从 Mac 上启动、卡在系统服务,推进到了 iOS 测试版。
可这一路,画面出现了,林克却黑了;海拉鲁就在眼前,脚下的地面却没了。
随后继续优化,Mac 跑到了接近 250 FPS,iPhone 和 iPad mini 也跑到了 60 FPS。先看后来跑起来的样子。

借来一座桥,还没到海拉鲁
Armigo 的起点是开源项目 d2r-mobile。它已经搭好了很重要的一段路:让 Switch 游戏的大部分程序在苹果芯片上直接执行,把系统请求和图形命令接到苹果的平台上。
这很像借来一座桥。桥不是我从零修的,但桥对岸原来通向另一款游戏,不会换个文件名就变成海拉鲁。
《旷野之息》要读自己的存档、启动自己的音频系统、发出另一套图形请求。已有的实现能接住一部分,剩下的就卡在那里。最初的启动记录,停在一个还没有实现的系统服务上。程序确实跑了,游戏还没开始。
我做的第一件事,是把这些路一段段接起来。账号和内容挂载接上了,还有声音;系统服务往前走了,显卡那边又在等。尤其是 NVN——Switch 的图形接口——原项目已经能服务自己的游戏,却没有覆盖《旷野之息》实际走到的那些用法。
补齐也不只是让一个报错消失。一个接口终于不报错了,下一帧可能就用另一种方式调用它。绘制、清屏、纹理更新、嵌套命令,得真的做对,游戏才肯往下走。
然后,它终于交出了一张截图。

一整块品红。
没有林克,没有神庙,连黑屏都不是。命令交出去了,截图也保存了,可这些「成功」加在一起,依然不是一张游戏画面。
神庙出现了,主角却是一团黑影
继续往前推,标题文字出现了。

再往后,复苏神庙出现了。到了这里,进展终于不需要靠日志解释:蓝色的光、石台、游戏界面,都能认出来。甚至已经到了可以操作林克的地方。
但主角全身都是黑的。

看上去很像贴图没加载。真正查下去,问题却藏在光照计算里:着色器翻译时,一串条件分支丢了后半截,本该生成的环境光变成了零。
所以,不是把画面调亮就能解决。算光的那段程序得先完整地执行。
修好之后,还是那座神庙,林克的皮肤、衣着和周围的细节终于能看见了。

光照这一关过去,神庙终于有了熟悉的样子。
但室外留下的另一组画面,又把「已经搬过来了」这句话拦住了。
不是湖,是地面没了
树和岩壁都在,远处也有海拉鲁的轮廓。乍一看,画面已经很完整。可本该铺着地面的地方出现了大片镂空,林克的腿还陷在土里。

游戏知道林克站在哪里,画面里的地面却没有跟上。地形高度要经过一条计算和传递链路,到了兼容层,有的数据没有正确交到显卡,有的计算结果又被后续更新覆盖。于是石头还在,地形却塌了。
只盯着最后一张图,很容易以为是模型少了一块。真正要修的是中间那条路:让地形高度正确到达,并且别再把已经算好的结果擦掉。

到这里,「能显示」和「能玩」才开始靠近。走路、转镜头、爬上岩壁,过去一张静止截图藏住的问题,会在动作里继续露出来。

声音和输入也得接上。会动的画面不会自动带来风声,更不会因为接了手柄就自己认得按键。这些事情逐一落到实处,海拉鲁才从一张截图变回一个可以走进去的世界。
搬的不是一个旧版本,也不只有本体
还有一层麻烦,光看截图看不出来。
这次的目标是《旷野之息》1.9.0。不是沿用旧版本已经摸清的地址和处理方式,换个版本号交差。与之前准备的 1.8.2 相比,几个程序模块都已经变化,原来确认过的地方,到了新版本还得重新检查。
DLC 也不能当成「多放几个文件」。游戏得先知道有哪些追加内容,再能把它们打开,和本体、更新后的数据一起使用。Armigo 接上了这条路,运行时已经能识别两项追加内容,并读取 DLC 的版本和地图资源。
所以,这次承担的是本体、1.9.0 更新和 DLC 一起工作的那套组合。它给兼容层出的题,远不止「把开场画出来」。
Armigo 这个名字,是 ARM 加上西班牙语的 amigo,朋友。Switch 和苹果设备有共同的处理器基础,但要让它们真正交上朋友,系统和图形之间的差异,一项也不会凭空消失。
跑快了,还不能让海拉鲁快进
画面逐渐对了,接下来才轮到「快」。
不少时间并没有花在海拉鲁本身,而是花在兼容层反复准备、搬运、打断绘制上。游戏只改了一小段数据,宿主却结束一整段绘制,再从头开始。把这些白忙活减掉,速度才往上走。
可帧数越高,也越容易冒出另一个问题:画面多画了,游戏里的时间会不会也跟着跑快?
如果林克跑步、物理和世界里的钟全都加速,那不是流畅,是快进。于是还得把游戏逻辑的步长和实际经过的时间对齐。后来那次接近 250 FPS 的短测里,现实过去约十秒,游戏里也过去约十秒,才让这个数字有了意义。
Mac 上省下的开销,到了手机还要换一种算法:不是只问能跑多快,还得问热起来之后怎么样。iPhone 的那次十五分钟路线测试跑到了接近 60 帧,但接电、约 29°C 的环境下,几分钟后也进入了较高热状态。帧率之外,还有功耗、散热和持续时间的账。
从 Mac 到 iOS,也不是给桌面程序换个图标。触控、声音、前后台切换,都得放进手机的使用方式里。52 小时到达的是 iOS 测试构建这个节点,后面的正确性和性能工作仍在继续。
跨过这道门之后
以前说「这游戏只能在那台机器上玩」,听着像一个天然事实。做完这段路再看,它更像许多具体问题叠出来的一道门:一处服务没接上,一条光照分支丢了,一份地形数据没送到。
把它们逐个处理,门就能打开一点。
但技术上能走出去,不会自动回答另一个问题:买下一款游戏,买到的到底是一部想长期保留的作品,还是一台机器上的访问资格?旧设备越来越难维修时,我们还能用什么方式回到那个世界?
我不想把这次实验写成「多跑了一百帧,所以平台就没有价值了」。《旷野之息》值得搬,恰恰因为海拉鲁本身值得再去一次。兼容层能把它接到新设备上,却不会替任何人创造下一个海拉鲁。
Armigo 做的,是把老朋友接过来。
至于下一位值得认识的朋友,还得有人去创造。