两年前,我写了一篇博客,讲述我如何“毫无理由”地将我的JavaScript游戏引擎移植到C语言。如今,我找到了理由:制作一款全新的N64游戏!成果就是《Xibalba 64》,一款类似《德军总部3D》的第一人称射击游戏。Modretro公司同意将其作为他们M64(一款现代N64克隆主机)的实体首发游戏,包含卡带、包装和说明书!
据我所知,这是自N64原始商业寿命结束以来,第二款获得实体发行的全新N64游戏。此前,Bitmap Bureau的《Xeno Crisis》——最初为世嘉MD开发,后来移植到众多平台——在2023年登陆了N64。自2002年的《托尼·霍克职业滑板3》以来,还没有其他新游戏在N64上发行过。
引擎:从JavaScript到C语言
Impact是我在2010年开发的JavaScript游戏引擎,专为2D动作游戏设计,处理图块、背景地图、精灵和碰撞检测。它非常简单,但足以应对各种需求。两年前,我将Impact用C语言重写,命名为high_impact。这个C移植版引入了“平台后端”的概念,负责底层细节,如打开窗口、创建绘图表面、读取输入等。开箱即用,high_impact自带两个平台后端(SDL2和Sokol),你可以为任一平台编译游戏。渲染后端也是模块化的,支持软件渲染、OpenGL或Metal(用于iOS/macOS)。这种设计使得添加新平台或渲染后端无需修改引擎其他部分,为N64游戏开发提供了完美起点。
N64硬件与Libdragon
N64是一台古怪的机器。除了93 MHz的MIPS CPU(大端序!),它还有两个协处理器:RDP(Reality Display Processor)是固定功能图形处理器,RSP(Reality Signal Processor)是可编程向量处理器。两者封装在一起,统称为RCP(Reality Coprocessor)。在N64早期,任天堂严格控制RSP的访问,仅由其官方库libultra使用。后来才允许游戏工作室编写自定义微码(实为MIPS汇编)。直接操作硬件几乎不可能,而使用libultra又面临版权诉讼风险。
幸运的是,N64自制社区近年来蓬勃发展,提供了强大的替代方案:Libdragon。它相当于N64的SDL,提供绘制精灵和三角形、声音输出、控制器输入等功能。我只用几个晚上就为high_impact构建了基于Libdragon的新平台后端,并用《Biolab Disaster》进行了测试。游戏代码无需修改,性能虽一般,但我的用法非常原始。
开发环境与硬件测试
Libdragon提供了编译器和构建ROM文件所需的一切。文档详尽,示例丰富,使用起来很愉快。不过建议使用preview分支,因为stable分支已严重落后。测试方面,模拟器至关重要。早期N64模拟器极不准确,尤其是RSP和RDP的模拟。如今,Ares的N64核心已相当接近真实硬件,但N64臭名昭著的慢速内存带宽仍只能在真机上测试。因此,你需要一台真N64和一张能运行任意.z64 ROM的烧录卡。开源的SummerCart64是个不错的选择,它支持SD卡和USB-C连接,可通过sc64deployer直接上传ROM。我将N64放在电脑旁,通过USB连接,并用10美元的USB模拟采集卡显示视频输出。这样,在真机上迭代只需编译并按下重置按钮。
游戏开发:从2D到3D的巧妙转换
《Xibalba》最初是我2014年为JavaScript引擎制作的演示,只有少量关卡、武器和敌人。而《Xibalba 64》要成为真正的游戏,需要更多内容。high_impact是2D引擎,但游戏是3D的。不过,由于没有高度差,它可视为2D游戏,类似《德军总部3D》。我巧妙地定义了vec3_t类型,使其兼容2D函数:
“c
typedef struct { float x, y; } vec2_t;
typedef union { vec2_t xy; struct { float x, y, z; }; } vec3_t;
“
这样,调用接受vec2_t的函数时,可直接传递pos.xy,而访问z坐标也毫无问题。移植现有关卡和敌人类型约两周完成,之后我花了几个月扩展游戏和优化渲染器。
渲染优化:纹理内存的挑战
N64仅有4 KB纹理内存,最大纹理仅64×64像素,上传延迟极高。许多游戏选择不使用纹理,但这不适合我的风格。因此,我精心安排图块绘制顺序以减少纹理上传,并利用Tiny3D库一次提交最多17个四边形。我设计了64位的渲染调用结构,用于批处理相同纹理的三角形,并在帧末排序提交。
可见性判断方面,我采用了射线投射:向场景发射320条射线,标记经过的图块。优化后,递归分割视野,直到相邻射线命中同一图块。天空盒仅用一张32×32纹理,通过巧妙拉伸实现。此外,我将图块表排列为单列,并尽可能使用4位索引色,以最大化纹理内存利用率。最终,游戏稳定运行在60 FPS,这在N64游戏中并不多见!四人分屏模式虽偶尔掉帧,但仍流畅,相比之下,《黄金眼007》在此场景常跌至个位数帧率。
音频:RSP加速的Opus解码器
音乐由好友Andreas Lösch制作,可在Bandcamp收听。卡带空间有限,压缩音频要么体积大,要么解码昂贵。Libdragon维护者Giovanni Bajo实现了RSP加速的Opus解码器——Opus是2012年发布的编解码器,比N64晚了16年!但它的计算开销仍不适合游戏内播放。目前更优方案是4位VADPCM格式,由Libdragon在RSP上透明解码。32 MB ROM中约31 MB用于声音和音乐。
发行与销售
Modretro此前推出过GBC克隆机Chromatic,并积极发行自制游戏。当他们宣布M64时,我看到了机会。原型完成后,我发了封邮件给客服,没想到一天内就收到发行主管回复。合同简洁,我要求允许日后开源引擎,他们欣然同意。开发过程中有些延迟,但M64运行完美,无需修改。封面由一位90年代负责德国Sierra包装的朋友设计,效果出色。说明书由我提供文字和插图,Modretro排版印刷。
销售数据不便透露,但游戏刚发布几天,表现不错。制作N64游戏虽不能让你辞职,但似乎能支付几次不错的假期。感谢Libdragon的Giovanni Bajo、Tiny3D的Max Bebök、N64brew Discord社区以及Modretro团队!
资源推荐
若想入门N64开发,以下资源很有帮助:n64.dev(资源合集)、N64brew Discord(友好社区)、Libdragon(系统库)、Tiny3D(3D图形库)、Pyrite64(可视化编辑器)。