2026 年如何做一款任天堂 64 游戏
文章摘要
Dominic Szablewski(phoboslab)两年前把自己的 JavaScript 游戏引擎移植到了 C,当时他的说法是「没有任何理由,就是好玩」。现在理由有了:他做了一款全新的 N64 游戏。
成品叫《Xibalba 64》,是一款类《德军总部 3D》的 FPS。Modretro 同意把它作为其 M64(一台现代 N64 复刻机)的实体首发游戏出版,配齐卡带、包装和说明书。据作者所知,这是 N64 商业寿命终结之后第二款获得实体发行的全新 N64 游戏——第一款是 Bitmap Bureau 于 2023 年移植过来的 Xeno Crisis;在那之前,N64 上最后一款新游戏还是 2002 年的《托尼霍克职业滑板 3》。
引擎部分。 Impact 是他 2010 年写的 JavaScript 引擎,面向 2D 动作游戏,处理图块表、背景地图、精灵和碰撞检测,很简单但底子扎实。两年前重写成 C 的版本叫 high_impact,它有「平台后端」的概念——平台层负责开窗、创建绘图表面、读取输入这类底层管道,自带 SDL2 和 Sokol 两个后端;渲染后端同样是模块化的(软件渲染器、OpenGL、Metal)。新增平台或渲染后端不需要动引擎的其他任何部分,这正是做 N64 游戏的完美起点。
硬件与平台库。 N64 是台古怪的机器:除了 93 MHz 的 MIPS CPU(大端序!),还有两个协处理器——RDP(固定功能图形处理器)和 RSP(可编程向量处理器),合称 RCP。任天堂早年严密看守 RSP 的访问权,只允许官方库 libultra 使用,后来才允许厂商为 RSP 写自定义微码。裸机编程基本不现实,而 libultra 虽然已经流传到了网上,用它则要冒版权诉讼的风险。所幸这几年 N64 自制软件圈势头很猛,现在有了 Libdragon——基本上就是 N64 版的 SDL,提供精灵和三角形绘制、音频输出、手柄输入等等。作者只花了几个晚上就在 Libdragon 之上搭好了 high_impact 的新平台后端,并用旧游戏 Biolab Disaster 做了测试:游戏代码一行未改就跑了起来,性能一般,但那是因为他当时以最幼稚的方式在使用硬件。
开发环境。 Libdragon 提供编译器和构建 ROM 所需的一切,文档全面,例子丰富——但要用 preview 分支,「稳定」的 trunk 分支已经无可救药地落后了。测试方面,N64 的模拟长期以来极不准确,多数模拟器只是在模拟 libultra(模拟「画一个三角形的意图」而非硬件实际会做什么),著名的 UltraHLE 就是这种「高层模拟」的代表。如今 Ares 的 N64 核心已经非常接近真机,RDP 和 RSP 都被完整模拟,连 RSP 时序都准确;但 N64 臭名昭著的低内存带宽仍然只能在真机上测。所以你还需要一台真 N64 和一张能加载任意 .z64 ROM 的卡带——开源的 SummerCart64 很出色,除了 SD 卡槽,它的 USB-C 口能直接连电脑、把 ROM 作为构建流程的一部分上传(注意某些 AliExpress 厂商会在板件用料上偷工减料)。作者的最终工作台是:N64 摆在 PC 旁通过 USB 连接,一张 10 美元的 USB 模拟采集卡把视频输出显示在桌面窗口里(Linux 上还得折腾 mpv 才能拿到低延迟)。这样迭代就只剩下「编译,然后按一下 N64 的重启键」。
游戏本身。 Xibalba 原本是他 2014 年为 JavaScript 引擎做的演示,当年 WebGL 还是新鲜事物,浏览器里的 3D 游戏颇为新奇,游戏很短,只有寥寥几关、几种武器和敌人。这次他想要的是真正的游戏而非演示,所以除了移植到 C 和 high_impact,还得扩充关卡、敌人和武器。虽然 high_impact 是 2D 引擎而游戏明显是 3D,但因为游戏没有高低差,本质上可以当 2D 处理——你完全可以从俯视角度玩它,所有物理、移动和射击都一样工作,这一点和《德军总部 3D》非常相似。技术上他用了一个匿名 union 定义 vec3_t(内含 vec2_t xy 与匿名的 struct { float x, y, z; }),这样调用只接受 vec2_t 的物理函数时可以零成本「转换」,同时 entity->pos.z 照样能直接访问。已有关卡和敌人类型的初步移植大约两周完成,之后又花了几个月扩充游戏和优化渲染器。整个过程中他保留了用 SDL2/Sokol 构建的能力,方便试玩游戏逻辑和敌人行为,还做了关卡文件改动即热重载的机制。关卡编辑器是 high_impact 自带的单个自包含 HTML 文件,唯一的真相来源仍是 C 源码——编辑器读取源码自动提取实体类型和支持的设置项。由于编辑器输出 JSON,而在 N64 上解析 JSON 会多出约 100 毫秒的加载时间,他写了个地图编译器把 JSON 编译成二进制结构体,并且为 N64 写大端序、为 x86(SDL2/Sokol/WASM)写小端序,各平台都无需字节交换。
渲染是最硬的部分。 Libdragon 的 rdpq_triangle() 可以直接绘制三角形,但真正该做的是把绘制调用提交给 RSP,用自定义微码做变换、光照、深度计算,再由 RSP 指挥 RDP 绘制。另一个优秀的开源库 Tiny3D 用简单的 API 包办了这一切。让画面出现是容易的,让它跑得快则完全是另一回事:N64 只有 4 KB 纹理内存,能上传的最大纹理仅 64×64 像素,更糟的是纹理上传的内存延迟惨不忍睹。《马里奥 64》等许多游戏的解法是尽可能渲染无纹理多边形,但这不适合他的美术风格,于是他只能极其小心地安排关卡图块的绘制顺序以最小化纹理上传次数。由于 Tiny3D 一次最多能提交 17 个四边形,浪费这个能力太可惜,他把相同纹理的三角形收集成 64 位的绘制调用(一个 union,位域打包了半透明标志、纹理索引、xy 坐标、宽高、顶点缓冲索引和四边形数量),每个调用只有 64 位,因此可以在帧末高效排序后一次性提交给 Tiny3D。
判断哪些部分可见,原版 JavaScript Xibalba 用的是传送门系统(把关卡分成扇区并预计算可见性),可行但过绘制偏多。这次他改用光线投射:向场景投射 320 条光线覆盖整个视野,每条光线把途经的图块标记进一张位图交给渲染器。后来又做了优化——递归二分 320 像素的视野,直到两条光线命中同一图块;这个过程中顺便检查途经图块是否缺少天花板,如果是就得画天空盒。有个趣闻:Xibalba 64 的天空盒只是一张 32×32 像素的纹理,「优美地涂抹在整条地平线上」。此外他把放不进单次上传的图块表排成单列并尽量用 4 位索引色,颜色更少意味着更多像素能塞进纹理内存,列式布局则保证每个图块能作为一整块连续内存上传。这些做完之后,游戏稳定运行在 60 FPS——这是很多 N64 游戏都做不到的;四人分屏模式虽不能全程 60 FPS,但依然流畅,相比之下《黄金眼 007》的分屏帧率常常掉到个位数。
音频。 音乐由他的好友 Andreas Lösch 制作。卡带空间很紧张,压缩音频要么很大要么解码太贵。Libdragon 维护者之一 Giovanni Bajo 英雄般地实现了一个 RSP 加速的 Opus 解码器——Opus 这个编解码器首次发布于 2012 年,比 N64 晚了 16 年,能跑起来本身就是奇迹,可惜在游戏运行时用还是太吃算力(顺带一提,此人后来还给 N64 实现了实时 H.264 解码器)。目前更实际的方案是 Libdragon 能在 RSP 上透明解码的 4 位 VADPCM 格式,压缩比不佳但远好过未压缩 WAV——32 MB 的 ROM 里有约 31 MB 是音效和音乐。
发行与销售。 Modretro 此前做过 Game Boy Color 复刻机 Chromatic,也很乐意出版业余开发者的新游戏。作者在有了可运行原型、并确信自己能把整个游戏做完(而且做好)之后,给 Modretro 的通用客服邮箱写了封信,出乎意料地在一天之内收到了发行负责人的回复。手续很少,合同直白,他要求增加了允许日后开源引擎的条款,对方欣然接受。虽然项目后期才拿到预生产版 M64,但那台机器如宣传所述工作正常,游戏不需要为 M64 做任何改动。盒绘由另一位朋友完成——此人在 90 年代负责过 Sierra 在德国发行的许多游戏(包括《半条命》)的包装。说明书由他提供文字和插图,Modretro 负责排版印刷。销售数字和合同细节他不能细说,游戏也才发售几天,但目前看起来不错:「做 N64 游戏大概不足以让你辞掉工作,但看起来能付得起几趟不错的假期。」文末他列出了入门资源:n64.dev、N64brew Discord、Libdragon、Tiny3D 和 Pyrite64。
HN 评论精华
这条帖子 490 分,是一次相当热闹的怀旧兼技术讨论,作者 phoboslab 也在评论区出没。
第五世代主机开发从未如此容易。 boricj 说他正在做 PlayStation 的自制软件(一个 voxel space 渲染器),现代工具链、编程语言、开发卡带和社区库让一切都不同了,「除了缺少一些便利(比如还得写个真机上的 GDB stub),跟现代嵌入式开发的体验没什么两样」。这引出了「当年他们是怎么做的」的追问,spicyjpeg 给出了本串最扎实的历史回答:跟今天的主机一样,你付一大笔钱、签 NDA,厂商给你 SDK 和开发硬件;第五世代之前,SDK 常常只有汇编器、调试器和寄存器级硬件文档,内核和引擎得游戏开发者自己实现。而索尼决定提供基于 GCC 的完整 C 工具链和一套极高层的库,一路抽象到现成的 3D 引擎和 MIDI 音序器;这在当时很不受欢迎(库又慢又低效,开发者习惯完全掌控硬件),但也让新手能快速上手,最终反而促成了 PS1 战胜工具更差的同辈。pjmlp 补充了历史视角:那个「糟糕的索尼 SDK」在当时被视为奇迹,正是它推动家用主机开发从汇编转向 C 作为主力语言(此前只有街机完成了这一转变)。inigyou 则解释了这与模拟的关系:高层模拟(HLE)不去模拟 SDK 函数拨弄的硬件寄存器,而是识别对 SDK 函数的调用并整体模拟,速度提升巨大——Windows 95 上模拟 N64 用的正是这招。
卡带上的锁定芯片这条串技术含量最高。 有人问为什么现在还能为老主机出新游戏,cubefox 指出当年第三方无法自制 N64 卡带正是因为锁定芯片。作者 phoboslab 亲自补充了一个绝妙的细节:每个 ROM 都需要一段被签名、并由锁定芯片验证的引导代码;任天堂的引导代码受版权保护不能用,所以 Libdragon 分发的引导代码,其签名是用跑在 GPU 上的暴力工具找哈希碰撞签出来的。yellowapple 补充了更疯的「开发版」:那是一段极小的已签名引导程序,只负责把「真正的」引导程序拷进内存然后跳转过去,这样即使你自己开发 IPL3 也不必为每次构建重新暴力破解签名;而且 libdragon 的 IPL3 不像官方那样盲目地把 ROM 头 1 MB 拷进 RDRAM,它期望后面的数据是一个完整的 ELF 可执行文件,会解析并把各段拷到指定位置。
「用 Claude 做 N64 游戏」引爆了一场小型价值观辩论。 stewx 说他正在用 Claude Opus 5 做一款 N64 游戏,「真的可行,我一行代码都没写,它能构建一个功能完整的游戏」,还让它写了个通过 GDB 远程串行协议驱动 Ares 模拟器的 skill 作为反馈回路。Flashtoo 直接质疑:你从中得到了什么?成品(一款为过时主机生成的游戏)的效用似乎很小,而乐趣本应在于了解 90 年代硬件这个时间胶囊的内部运作。这条底下的回答很有意思:hnlmorg 说小时候不被允许碰电脑时他画 8 位系统的游戏关卡,「人们也能从游戏设计中获得乐趣,不只是钻研技术规格」;gambiting 作为做过 PSP 和 Vita 游戏的开发者说「就是不一样」——看着自己的作品在一台小掌机上运行,让一台只有 2 MB 内存的设备按你的设想运行你的游戏,「超级酷,对我个人而言极度令人满足」;pelasaco 补了个刀:「这里的反转是——游戏设计也是 Claude 做的 :)」。
gambiting 后来还贡献了整条帖子里最有分量的一段自白,起因是有人担心「工具太易用会产出未优化的垃圾」。他自称职业生涯一直在做游戏引擎底层,参与过销量 2000 万份以上的 3A 游戏,日常工作是修「Switch 上 RHI 线程比应该的多花 0.5 毫秒」这类问题。他说几年前他会持相同立场,但现在心态平和多了:很多所谓的「friendslop」游戏技术上很糟糕,但它们依然给人带来快乐、依然让人和喜欢的人一起大笑;他最珍视的记忆之一,是读到玩家说他们期待着下班后和朋友一起玩他做的游戏。「说这(工具变简单)是坏事——对我个人而言那是在设门槛。说你不会写渲染器或物理系统就不能做游戏,这对那些想做游戏但不知道怎么做的人太不友好了。」他还补了一句商业观察:Epic 允许你免费使用虚幻引擎直到游戏开始赚大钱,你可以开公司、雇人、开始做想做的游戏而不必为工具付一分钱,「世界上很少有公司允许你这么干」。
「游戏已死」的怀旧情绪与反驳。 shoobiedoo 说 N64/PS1 时代有种迷人之处——两台风格迥异的机器,你扫一眼就知道画面出自哪台;他给自己和儿子买了 MiSTer,玩烂了《马里奥卡丁车 64》,「他大概也染上了我『游戏已死』的观点,对新主机新游戏没什么兴趣了」。pizza234 反驳得最系统:会觉得游戏已死,往往是因为跟现代游戏的唯一接触是关于少数 3A 大作的新闻标题;实际上游戏版图从未如此丰富——入行门槛降低让擅长设计但不擅编程的人有了机会,3A 预算增长让喜欢大制作的人有更大的游戏,复古现代风的小厂也活得不错,「他们甚至还在出商用的 Commodore 64 游戏 o_O」。officeplant 认为该改叫「3A 游戏已死」,问题在于私募股权、股东和贪婪;LarsDu88 则提醒这是玫瑰色滤镜——90 年代的 3A 开发要残酷得多,并举了 Sonic Xtreme 半个团队病倒请医疗假的例子。pjmlp 补充:当年也有大量烂游戏,而且你只能靠盒子封面猜游戏是什么,运气好有杂志评测或封面盘上的试玩版,「你出门把辛苦攒的钱交出去,然后拿到一个垃圾游戏,不能退钱」。中间有一小段试图把 3A 的问题归因于「工作室雇了不喜欢玩家的人」的性别政治发言,被 officeplant 一句话挡了回去:「你不用搞 GamerGate 那套胡话,也能找到大把伤害 3A 市场的问题——私募股权、股东和贪婪的破坏力大得多。」
几条技术追问与作者的回答。 crest 认为在 N64 上做光线投射器很奇怪,「这硬件简直是在求着你喂它带纹理的多边形」;phoboslab 澄清:所有几何体确实都是作为带纹理的多边形渲染的,光线投射这一步只用来确定可见性——但他也承认「N64 确实不太适合这类游戏(或者说任何 2D 游戏),我开始做的时候不知道这一点」。有人问 M64 卡带是否兼容原版 N64,作者回答:兼容,游戏主要就是在一台原版 N64 上开发的;不过 Modretro 的卡带目前只能在 NTSC 制式的 N64 上工作,据说下一批产品会同时支持 PAL。dabluecaboose 作为刚买了 M64 的玩家回答了「这个受众真的会买实体卡带吗」的疑问:会,他架子上就摆着全新的 Xeno Crisis,「当然也有一批人更愿意买张 SummerCart 然后下载所有 ROM,但我个人喜欢更用心、更有意图的电子产品」。ayanb 留下了传播度最高的一句吐槽:「2026 年的 Web 开发:4 MB 的 JavaScript 渲染一个按钮。2026 年的 N64 开发:1 MB 装下整个 FPS。」
最后一个绕不开的背景:pelasaco 指出这款游戏出现在 Palmer Luckey 的一段视频里(Modretro 是他的公司),「这家伙居然有时间和精力搞这种支线任务,这是热爱」;也有人因 Luckey 的军工背景发了政治性评论并被标记(flagged),barrowclift 的回应是「这篇文章不是关于 ModRetro 的,请讨论实际内容而不是跑题的政治长篇大论」。