
2026 年如何制作任天堂 64 游戏?从移植引擎到发行,全流程揭秘!
2026 年 8 月 4 日,周二,多米尼克·萨布莱夫斯基(Dominic Szablewski),[@phoboslab](https://x.com/phoboslab)分享了如何制作任天堂 64 游戏。
两年前,他无缘无故地将自己的 JavaScript 游戏引擎移植到了 C 语言,相关内容记录在 [《无端将我的 JavaScript 游戏引擎移植到 C 语言》](/log/2024/08/high_impact) 中。后来他找到了这么做的理由:制作一款全新的任天堂 64(Nintendo 64,简称 N64)游戏!
最终成果就是 [《希瓦巴 64》(Xibalba 64)](https://modretro.com/products/xibalba-64),这是一款类似《德军总部 3D》(Wolfenstein 3D)的第一人称射击游戏(FPS)。Modretro 公司同意将这款游戏作为他们 M64 主机(一款现代版的 N64 复刻机)的首发实体游戏进行发行,届时会配有游戏卡带、精美包装和说明书!
据了解,这是自 N64 主机结束其最初的商业生命周期以来,第二款以实体形式发行的全新 N64 游戏。此前,由 [Bitmap Bureau](https://www.bitmapbureau.com/) 开发的著名游戏 [《异星危机》(Xeno Crisis)](https://modretro.com/products/xeno-crisis) 于 2023 年登陆 N64。该游戏最初是为世嘉 Mega Drive 主机开发的,后来又在众多其他主机上发行。自 2002 年《托尼·霍克滑板 3》(Tony Hawk's Pro Skater 3)之后,N64 就再没有发行过新游戏。
游戏引擎
[Impact](https://impactjs.com/) 是他在 2010 年开发的一款 JavaScript 游戏引擎,专门用于开发 2D 动作游戏,能够处理图块集、背景地图、精灵图和碰撞检测等功能。它虽然简单,但为开发者提供了一个坚实的基础,可用于实现各种创意。
两年前,他用 C 语言重写了 Impact 引擎,只是觉得挺有趣的。
这个 C 语言版本的移植项目 [high_impact](/log/2024/08/high_impact) 引入了“平台后端”的概念。平台后端负责处理底层的基础工作,比如打开窗口、创建绘图表面、读取输入等。high_impact 自带了两个平台后端(SDL2 和 Sokol),开发者可以选择其中任意一个来编译游戏,这使得 high_impact 游戏能够在多种不同设备上运行。
high_impact 的渲染后端也是模块化的。开发者可以使用软件渲染器、OpenGL 或 Metal(适用于 iOS/macOS)来编译游戏。而且,在不修改引擎其他部分的情况下,还可以添加对新的平台后端或渲染后端的支持。
这一切都让 high_impact 成为开发 N64 游戏的理想起点。
N64 硬件与平台库
N64 是一款独具特色的主机。除了主频为 93 MHz 的 MIPS CPU(采用大端字节序!)之外,它还配备了两个协处理器,分别用于处理图形、声音等功能:
- “现实显示处理器”(Reality Display Processor,简称 RDP):这是一个固定功能的图形处理器。
- “现实信号处理器”(Reality Signal Processor,简称 RSP):这是一个可编程的矢量处理器。
这两个处理器都封装在同一个物理芯片中,通常被称为“现实协处理器”(Reality Coprocessor,简称 RCP)。
在 N64 主机上市的最初几年里,任天堂严格限制对 RSP 的访问权限。只有任天堂官方认可的平台库“libultra”才能使用 RSP。直到后来,任天堂才允许游戏工作室为 RSP 编写自定义的“微代码”(实际上就是 MIPS 汇编代码)。
要让硬件稳定运行并非易事,而且 RDP 的指令既古怪又复杂。因此,在裸机上直接开发游戏几乎是不可能的。近年来,任天堂官方的“libultra”库虽然已经在互联网上流传,但使用它可能会面临版权诉讼的风险。
幸运的是,近年来 N64 自制游戏社区发展迅速,现在有了一个非常出色的替代方案:[Libdragon](https://libdragon.dev/)。
Libdragon 就像是 N64 版的 SDL 库,它提供了绘制精灵图和三角形、输出声音、读取控制器输入等诸多功能。
他只花了几个晚上的时间,就在 Libdragon 的基础上为 high_impact 引擎开发了一个新的平台后端。他用 [《生化实验室灾难》(Biolab Disaster)](https://github.com/phoboslab/high_biolab) 这款游戏进行了测试。游戏代码无需修改,但性能表现一般,毕竟只是以最基础的方式使用了 N64 的硬件。
开发环境
Libdragon 提供了编译 N64 游戏 ROM 文件所需的编译器和其他工具。其 [安装说明](https://github.com/DragonMinded/libdragon/wiki/Installing-libdragon) 和其他文档都非常全面且易于理解,同时库中还附带了许多示例代码,方便开发者入门。
总体而言,使用 Libdragon 进行开发是一件很愉快的事情。不过需要注意的是,建议使用 `preview` 分支,因为“稳定”的 `trunk` 分支已经严重落后了。
在测试方面,一款优秀的模拟器至关重要。长期以来,N64 模拟器的准确性一直不尽如人意,尤其是对 RSP 和 RDP 协处理器的模拟不够精确,这是导致大多数问题的根源。
大多数模拟器只是模拟了任天堂的平台库 libultra,它们模拟的是绘制三角形的“意图”,而不是硬件实际的操作。虽然这种模拟方式在早期使得模拟器能够运行起来,但并不准确。著名的 [UltraHLE](https://en.wikipedia.org/wiki/UltraHLE)(“超高级别模拟器”)在 N64 主机的生命周期内就已经发布,但它引发了很多问题,并导致了后续的法律诉讼。
如今,[Ares](https://ares-emu.net/) 模拟器中的 N64 核心已经非常接近真实硬件,它能够完全模拟 RDP 和 RSP,甚至包括 RSP 的精确时序。不过,N64 臭名昭著的低内存带宽问题,仍然只能在真实硬件上进行测试。
因此,需要一台真正的 N64 主机和一个能够运行任意 `.z64` ROM 文件的卡带。开源的 [SummerCart64](https://github.com/Polprzewodnikowy/SummerCart64) 就非常不错,而且有很多不同的厂商都在生产。需要注意的是,有些厂商(尤其是阿里巴巴国际站上的一些商家)可能会在电路板的组件上偷工减料。
SummerCart64 带有常见的 SD 卡插槽,用于存储 ROM 文件。而它对于开发来说最出色的地方在于其 USB-C 接口:可以直接将它连接到电脑上,并使用 [sc64deployer](https://github.com/Polprzewodnikowy/SummerCart64/releases) 在编译过程中直接上传 ROM 文件。
最终,把 N64 主机放在电脑旁边,通过 USB 连接,然后使用一个价值 10 美元的廉价 USB 模拟采集卡,将 N64 的视频输出显示在电脑桌面的窗口中。在 Linux 系统上,花了一些时间调整 `mpv` 播放器的设置,才实现了低延迟的输出。
有了这样的设置,在真实硬件上进行迭代开发就变得非常简单,只需要编译代码并按下 N64 的复位按钮即可。
游戏开发
2014 年,他最初制作 [《希瓦巴》(Xibalba)](/log/2014/07/xibalba-a-webgl-first-person-shooter) 是为了展示他的 JavaScript 游戏引擎。当时 WebGL 还是一项热门的新技术,在浏览器中运行 3D 游戏是一件非常新奇的事情。这款游戏非常简短,只有少数几个关卡、武器和敌人类型。
相比之下,他希望《希瓦巴 64》成为一款真正的游戏,而不仅仅是一个演示。因此,他不仅要将游戏移植到 C 语言和 high_impact 引擎上,还要增加更多的关卡、敌人类型和武器。
`high_impact` 是一个 2D 游戏引擎,但《希瓦巴 64》显然是一款 3D 游戏。不过,由于游戏中没有高度变化,所以大部分情况下可以将其视为 2D 游戏。从概念上讲,可以以 2D 俯视视角来玩《希瓦巴 64》。当然,这样玩起来可能没那么刺激,但所有的物理效果、移动和射击机制都是一样的。在这方面,这款游戏与《德军总部 3D》非常相似。
high_impact 的许多物理函数都期望接收一个包含 `.x` 和 `.y` 分量的 `vec2_t` 参数。但在绘制时,绝对需要一个 3D 位置,所以他定义了一个 `vec3_t` 类型,并修改了 `entity_t` 类型。
现在,每当需要调用一个接受 `vec2_t` 参数的函数时,可以免费“转换” `vec3_t` 类型。
由于内部的 `vec3_t` 结构体是“匿名”的,仍然可以直接访问所有值,例如 `entity->pos.z` 可以正常工作。
将现有的关卡和敌人类型进行初步移植的过程非常顺利,大约两周就完成了。然后,又花了几个月的时间来扩展游戏内容并优化渲染器。
Libdragon 的大多数函数都能自然地融入到新的平台和渲染后端中,但不得不修改 high_impact 的其他一些部分,以绕过其混音器(Libdragon 有自己的混音器,由 RSP 加速)和图像加载器。
在整个开发过程中,始终保留了使用 SDL2 或 Sokol 后端构建游戏的能力。这对于测试游戏逻辑和敌人行为非常有帮助。为了制作关卡,还实现了一个简单的热重载机制,每当关卡文件发生更改时就会触发。
与 high_impact 捆绑的关卡编辑器是一个独立的 HTML 文件。对其进行了大量扩展,以更好地支持光照贴图,为实体显示实际的精灵图(而不仅仅是方框),添加实体设置的描述以及提供其他一些小功能。C 源代码仍然是唯一的事实来源,关卡编辑器会读取它并自动提取实体类型和支持的设置。
由于关卡编辑器仍然使用 JSON 文件,构建了一个小型的地图编译器,它可以读取 JSON 文件并生成二进制数据。虽然在 N64 上加载 JSON 文件是可行的,但这会增加大约 100 毫秒的不必要加载时间。因此,在构建过程中,每个 JSON 关卡文件都会被转换为一个结构体。
关卡编译器会以大端字节序为 N64 写入这些值,以小端字节序为 x86(SDL2、Sokol、WASM)写入,这样就可以在所有平台上轻松读取数据,而无需进行字节交换。
渲染
Libdragon 本身提供了一个绘制三角形的函数:`rdpq_triangle()` 可以将一个三角形绘制调用插入到 RDP 队列中。虽然这种方法可行,但更好的做法是将绘制调用提交给 RSP,使用一些自定义的微代码来执行变换、光照、深度计算等操作,然后让 RSP 指示 RDP 最终绘制三角形。
RDP 和 RSP 的细节对他来说仍然很陌生,但幸运的是,另一个出色的开源库 [Tiny3D](https://github.com/HailToDodongo/tiny3d) 提供了一个简单易用的 API,处理了所有这些复杂的操作。在屏幕上显示内容相对容易,但要让它具有良好的性能则是另一回事。
N64 臭名昭著的是只有 4 KB 的纹理内存,最大可以上传的纹理尺寸仅为 64×64 像素。更糟糕的是,纹理上传的内存延迟非常高。一种解决方案是像《超级马里奥 64》(Mario 64)和许多其他游戏那样,尽可能渲染无纹理的多边形。
但这种方法并不适合他的游戏风格,因此他必须非常小心地安排关卡图块的绘制顺序,以尽量减少纹理上传。此外,Tiny3D 一次最多可以加载和提交 17 个四边形,如果不充分利用这一点就太浪费了。因此,他最终将具有相同纹理的三角形批次收集到 64 位的绘制调用中。
这里的 `vbi` 是伴随的顶点缓冲区索引,`len` 是此调用中的四边形数量。由于每个调用只有 64 位宽,可以在帧结束时高效地对它们进行排序,并将其发送给 Tiny3D。
但在进行所有这些操作之前,他必须首先确定关卡中哪些部分是实际可见的。最初的 JavaScript 版《希瓦巴》使用了一种门户系统,将每个关卡划分为多个区域,并预先计算出从当前区域可以看到哪些区域。这种方法效果不错,但产生的过度绘制比他预期的要多一些。
因此,他选择了另一种方法:射线追踪。是的,游戏只是向场景中发射 320 条射线,覆盖整个视野范围。每条射线会在一个位图中标记经过的图块,然后提交给渲染器。
后来,他对射线追踪进行了进一步优化,通过递归地划分 320 像素的视野范围,直到两条射线击中同一个图块为止。在这个过程中,他还会检查经过的图块是否缺少天花板,如果是,则需要绘制一个天空盒。
有趣的是,《希瓦巴 64》中的天空盒只是一个 32×32 像素的纹理,它被巧妙地拉伸到整个地平线。
作为另一种优化措施,他将每个无法一次性上传的图块集排列成一列,并尽可能使用 4 位索引颜色。使用较少的颜色可以让更多的像素放入纹理内存中,而列布局则确保每个图块可以作为一个连续的内存块进行上传。
通过所有这些优化,游戏能够以稳定的 60 FPS 运行,这是许多其他 N64 游戏都无法做到的!
四人分屏模式虽然并非始终能达到 60 FPS,但仍然保持流畅。相比之下,著名的《黄金眼 007》(GoldenEye 007)在四人分屏模式下帧率常常会降至个位数。
声音与音乐
和他其他所有游戏一样,他的好朋友安德烈亚斯·勒施(Andreas Lösch)为《希瓦巴 64》创作了出色的音乐。可以在 [Bandcamp 上收听完整的《希瓦巴 64》原声带](https://nofatenetmusic.bandcamp.com/album/xibalba64)。
游戏本身还内置了一个音乐播放器,可以在单人战役中解锁它。
游戏卡带的存储空间有限,即使是压缩后的音频文件通常也要么很大,要么解码成本过高。
在一次了不起的尝试中,Libdragon 的维护者之一乔瓦尼·巴乔(Giovanni Bajo)——一位在 N64 相关领域堪称大师的人物——实现了一个由 RSP 加速的 Opus 解码器。要知道,Opus 是一种于 2012 年首次发布的音频编解码器,这比 N64 问世晚了 16 年!令人惊讶的是它居然能够工作,但遗憾的是,在游戏运行过程中使用它仍然需要较高的计算资源。
(题外话:乔瓦尼·巴乔后来还为 N64 实现了一个实时 H.264 解码器。)
目前更好的选择是一种简单的 4 位 VADPCM 格式,Libdragon 可以在播放过程中通过 RSP 透明地对其进行解码。当然,这种格式的压缩比并不理想,但比未压缩的 WAV 文件要好得多。在 32 MB 的 ROM 中,大约有 31 MB 被用于存储声音和音乐。
在《希瓦巴 64》发布后,他开始着手实现另一种音频压缩格式,以更好地平衡存储空间、音质和复杂度之间的关系。关于这方面的更多内容,他将在下一篇博客文章中详细介绍!
发行与销售
Modretro 之前推出过一款 Game Boy Color 复刻机——Chromatic,它兼容所有现有的 Game Boy 和 Game Boy Color 游戏,并且该公司非常热衷于发行由业余开发者制作的新游戏。
当他们宣布推出 M64 主机时,他认为这是一个绝佳的机会。一旦他有了一个可行的原型,并且确信自己能够完成整个游戏的开发(并让它变得出色),他就给 Modretro 的通用客户服务邮箱发了一封邮件。令他惊讶的是,他在一天之内就收到了发行部门负责人的回复。
整个流程中的官僚程序很少,合同条款也很清晰明了。他提出了一些修改建议,以便日后能够将游戏引擎开源,Modretro 很乐意满足他的要求。
当然,和所有项目一样,开发过程中出现了一些延迟,他在开发后期才收到一台预生产版的 M64 主机。但这并不影响,M64 主机的表现符合预期,游戏无需为 M64 进行任何更改。
Modretro 还提出可以帮忙设计游戏包装盒的艺术图案,但他的另一位朋友主动承担了这项工作。他后来告诉我,在上世纪 90 年代,他曾负责德国 Sierra 公司发行的许多游戏的包装设计,其中包括《半条命》(Half-Life)。所以毫不奇怪,《希瓦巴 64》的包装盒艺术图案最终效果非常出色!
关于游戏说明书,他向 Modretro 提供了文字内容和插图,他们负责排版印刷,整个过程非常顺利。可以在 [《希瓦巴 64》的商店页面](https://modretro.com/products/xibalba-64) 上查看 PDF 版的说明书。
他目前还不能详细谈论销售数据或他与 Modretro 的合同细节,而且游戏刚刚发布几天,但到目前为止情况看起来还不错。当然,制作 N64 游戏可能无法让你辞去工作,但看起来它足以让你享受几次愉快的假期。
非常感谢 [Libdragon](https://libdragon.dev/) 的乔瓦尼·巴乔、[Tiny3D](https://github.com/HailToDodongo/tiny3d) 的马克斯·贝博克(Max Bebök)、整个 [N64brew Discord](https://discord.gg/WqFgNWf) 社区,当然还有 Modretro 团队,是你们让这一切成为现实!
以下是游戏的最终预告片。
资源推荐
如果你想开始进行 N64 游戏开发,以下这些资源可能会对你有所帮助:
- [n64.dev](https://n64.dev/):一个包含所有 N64 开发相关内容的资源集合。
- [N64brew Discord](https://discord.gg/WqFgNWf):一个非常友好且乐于助人的社区,许多库的开发者都活跃在这个社区中。
- [Libdragon](https://libdragon.dev/):N64 开发的必备系统库。
- [Tiny3D](https://github.com/HailToDodongo/tiny3d):一个简单而快速的 3D 图形库。
- [Pyrite64](https://github.com/HailToDodongo/pyrite64):一个用于创建 3D 游戏的可视化编辑器和运行时环境。


被折叠的 条评论
为什么被折叠?



