Aioga
AI资讯 / 行业动态
返回 AI资讯

开发者用 Claude Fable 5 在 Claude Code 中将 1993 年 Amiga 游戏 Babylonian Twins 移植到 Godot

Hacker News 热门(buzzing.cc 中文翻译)Aioga 编辑团队2026-09-04T00:07:47.000Z热度 72

作者让 Claude Fable 5 在 Claude Code 中分三步移植其 1993 年 Amiga 游戏:34,000 行 C++ 一个晚上迁入 Godot 4,72,...

行业动态Hacker News 热门(buzzing.cc 中文翻译)

今日 AI 情报摘要

作者让 Claude Fable 5 在 Claude Code 中分三步移植其 1993 年 Amiga 游戏:34,000 行 C++ 一个晚上迁入 Godot 4,72,758 行无注释

68000 汇编先用 vasm 重建出与发售版字节一致的二进制再移植,并把 1993 原作作为第二启动项嵌入新游戏。

中文正文 · AI 翻译

1993年,在巴格达,我在一台Amiga 500上制作了一款名为《巴比伦双子》的游戏:512KB内存,没有硬盘,接到电视上。我那时是二十多岁的工程专业学生。纯68000汇编,每一个精灵和每一条扫描线都是手工完成的。Murtadha Salman负责绘制艺术,Mahir AlSalman作曲。我们当时受到制裁。没有互联网,没有游戏开发资源,只有一本Amiga硬件参考手册,我用它直接编程硬件,每天只有几个小时的电力。由于内存小,不断交换软盘,以及50°C的夏天,我的软盘驱动器坏了三次。

左:1993年,在Amiga上。右:2026年,同一个网关。

在Amiga上,“手工”意味着游戏运行时不会向操作系统请求任何东西。启动时保存中断向量,关闭OS中断,完全掌控整台机器:

“从AMIGA获取系统”是我1993年的注释。从那时起,显示完全由游戏自己的copper列表控制(Amiga的可编程视频协处理器),根据精灵和天空颜色实时重写。通过直接写入blitter寄存器并等待其完成标志来移动图块。操纵杆直接从硬件端口读取,射击按钮是CIA芯片上的一个引脚。操作系统只在关卡间返回,用于从磁盘加载下一关的文件,然后再次关闭。

这是伊拉克制作的第一款商业游戏,并且很长一段时间内,很少有人玩过。康懋达破产,加上制裁吓跑了出版商,所以成品游戏长期放在架子上。一个Amiga论坛在2008年通过我兄弟上传到YouTube的视频找到了它,并追踪到我要软盘;讨论帖仍然存在:https://eab.abime.net/showthread.php?t=39120。

这款游戏曾在2010年被手工移植过一次。同一团队为iPhone重建了它,使用全新引擎编写,大约34,000行C++代码,经过几个月的夜晚和周末的努力。苹果和谷歌都进行了推荐,其下载量超过两百万次。故事在这里:https://babyloniantwins.com/story.

我没有做这个移植。我要求的,每晚玩结果,说出感觉不对的地方,做出少数需要1993年现场人员的决定。文件格式和汇编读取是AI的工作,关于如何携带三十年前代码的决策也是,速度快得我都跟不上。这篇帖子是我几周后坐下来阅读自己游戏被改动时发现的。有些地方是错的,我几周后才注意到。

我以前试过这个方法。大约一年前,我给一个早期模型用同样的Amiga材料,让它帮我理解我的二进制关卡地图。最终还是做到了,但花了好几轮时间,我也给了很多提示。

后来《Claude Fable 5》发货了,我给了它同样的文件。

测试是有意为之。我猜 LLM 训练集里几乎没有 Amiga 汇编代码。如果模型能更好地计算而非回忆,这才是关键。

7月4日周末快到了,所以我计划了三个步骤,每一步都以之前的工作为条件。

第一步,安全问答:我自己的2010年引擎,34,000行C++,迁移到了Godot 4。这就是控制。

第二步,不公平的要求:为一台已停产、没有任何评论且与C++毫无关联的机器,使用原始72,758行68000代码汇编。在Godot中也重建它,使用Amiga原版的50 Hz。

第三步,贪婪的请求:把第二个放进第一个里面,这样买现代游戏就能拿到1993年原版作为第二个可以启动的游戏。

这三种方法都行。那个经过多轮和我一年前修正的关卡格式一次性完成,我没有任何提示。

我用Claude Code运行,所以它有终端和我的文件系统。它可以编辑文件,运行汇编器,构建游戏,启动游戏并读取返回内容。当我在下面说它重建了1993年的二进制文件并检查它们时,它是通过运行vasm并对输出进行差分来实现的。

早期它给游戏添加了一套命令行标志,这样游戏就能不用我也能玩:

这就把“跳跃感觉对吗”变成了机器能读取的内容:

它还可以在显示任何内容之前运行两个无头检查:一个会编译所有脚本,另一个会构建所有关卡并报告失败情况。在Amiga端,它驱动了真实的工具链,用vasm进行汇编,并用FS-UAE启动结果。没有自动化的部分:现代移植版没有图像对比(它会截屏,我查看它们),也没有检查游戏的感觉是否正确。

星期三晚上,安全请求。时间戳,未经编辑:

从空项目到可操作角色只用了二十一分钟。那晚它移动的每一行都是我在2010多年里写的。我带着困惑上床睡觉。

之后花了大约三天才让游戏感觉正确:跳跃弧线和蹦床时机,以及奖励乱按的碰撞检测,分别在7月2日、3日和4日通过批量修复完成。

我并不是独自测试的。我的十三岁儿子和我一起玩每个版本。他一直知道我做了这款游戏,这是他成长过程中关于父亲的一个事实,但他从未见过我开发它的过程。测试变成了一件我没计划的父子事情,这是我整个项目中最喜欢的部分之一。

所有游戏状态都以瓦片单位存储(1.0 = 一个48像素瓦片),更新以固定的60Hz运行,因为2010年的iOS版本是60Hz。这很重要,因为原版是逐帧以乘法方式应用阻力的:

每秒乘以0.85六十次,你会得到一种摩擦量;每秒乘以五十次,你会得到另一种。在不同的刷新率上移植,游戏中每条加速度曲线都会改变。没有崩溃,只是永远感觉不对,你通过阅读差异也找不到。在60Hz下,这个常数可以原封不动地移植。这也是为什么1993年的重建版以50Hz运行,而现代版以60Hz运行:两套手工调试的数值,每套只在其各自的时钟下正确。它保留了两个时钟。我本来会想把它们整理成一个。

Godot 自带 CharacterBody2D 和 move_and_slide(),每个教程都告诉你使用它们。这个移植版却都没用在玩家身上。原版有自己手写的移动代码,把它建立在别人的物理系统上会感觉有些不对劲,而且问题追查起来挺痛苦。玩家只是一个普通的 Node2D,而那段 150 行的碰撞例程几乎逐行照搬过来,包括我十五年前凭感觉挑的 fudge 数值,以及我写给未来自己的注释:

没人去整理那些零散的 0.49。没有测试,也没有文档;那些注释就是规格说明。

到 7 月 5 日周日下午,我交出我实际上想测试的东西。26 个文件共有 72,758 行代码,为只有 512 KB 内存的机器编写,由我为自己写,带着一个从未指望别人会看的人的注释习惯。没有文档。2008 年转存到现代存储设备时,每个长文件名都被缩短了,所以每个 include 指向的名字都不存在了。五个关卡源文件中有一个在数据表中途截断。没有其他副本。

在移植任何东西之前,它让 1993 年的源代码再次能够编译,用 Apple Silicon Mac 上的 vasm,直到输出的字节与发布的二进制文件完全一致。

从一堆文件到第一版匹配发布字节的重建只用了十五分钟。我在 ASM-One 中写的这些代码,其方言与 vasm 的不同会导致字节变化:ASM-One 把 cmp #4,d0 编码为 CMPI,而 vasm 选择了不同但同样有效的编码,因此告诉它不要优化是必要但不充分的。与其编辑我的源代码,它写了一个预处理过程来桥接五处此类差异,并按文件重建损坏的文件名映射。

最费劲的是 org。没有链接器,也没有重定位,关卡源代码手动布局 Amiga 的内存,一地址一地址地安排:

一级地图使用了 74,400 字节中的 74,752 字节,余量为 352,除了我在 1993 年,没有人检查过它。 (SahamR-grb 将对象的行为作为一个命名偏移附加;saham 在阿拉伯语中是箭头的意思。) ASM-One 的 org 也可以将位置计数器向后移动,而 vasm 做不到。第一次变通方法有一个情况出错:在回绕块内的 ds.b 800,ASM-One 将其视为“跳过 800 字节”,但写出时却是 800 字节的零。该文件之后的所有内容,包括铜列表,都比原始二进制文件的位置偏离 944 字节。游戏被组装并启动,但显示了错误的内容。

即使在那之后,一些块仍然不匹配,分散在变量区域,大约有 108 字节。这些字节解释了发货文件的来源。ASM-One 汇编到内存中,而游戏通过将该内存保存到磁盘上来获得磁盘版本,这是在游戏运行后进行的。因此,发货文件是游戏已经运行过的快照,而不是干净的汇编输出。一次新的汇编在这些变量中是零,因为还没有任何东西设置它们;发货磁盘中保存了当时机器上的内容。代码先写入它们再读取,因此这些零是无害的。

当时我读到那一行后就继续,等待实际游戏。我用好几周才明白这是项目中最重要的事情,而且没人要求过它。从那时起,关于这款游戏的每一个断言都可以通过对比字节来解决。我自己也不会这么做。我已经有了二进制文件,在十八年里从源代码重建它们,从来不觉得值得花一个下午去做。

对于它所去的每种格式,我都会转到读取字节的代码,并从那里逆向。关卡加载器是 1,652 行无注释的 68000 代码,这就是为什么我总是倾向于使用十六进制编辑器。

一个关卡是一张瓦片网格:一个长长的数字列表,每个数字表示“在这里放置第 47 张图片”,这是我个人 1993 年的布局。这是我和老模型一年前反复推敲出的格式。

这里是构建关卡所用的完整瓦片集,共 256 个,每个 16×16 像素,用于第一关:

The complete 16x16 tile set for level one of the 1993 Amiga game: stone blocks, ladders, water, palm fronds, decorative brickwork

以及从这些瓦片拼出的第一关的一部分:

A horizontal slice of level one rendered from the extracted map data

输入是一份没有标题和维度的数字列表,位于一个压缩块中。这次我没有解释任何内容。它找到了绘图例程,读取了网格的遍历方式,从文件其他地方的常量得出了宽度和高度,并第一次尝试就生成了所有五个关卡的正确地图。

然后,它从提取的数据重新渲染每个关卡,并将结果逐像素地与我在2020年制作的完整关卡截图进行比较。对于不匹配的情况,它去寻找原因,发现了两个铜制效果:天空渐变和水颜色循环。在考虑这两者之后:五个完整关卡图像,无差异像素。单单关卡一就有600个瓷砖宽,9,600个像素。

绘制关卡只是地图单元功能的一半。每个单元是一个16位字,而图片只是其中较小的部分:

属性是关卡的隐形物理。1表示坚实地面。2和3可以攀爬。10到13都表示“会造成伤害”,有四个代码是因为击退需要方向。14会立即致死。63是门。这些内容都没有记录在任何地方。它是通过两个例程读取同一字来恢复的,每个例程展示了自己的半部分:绘图循环屏蔽低字节,碰撞检查则相反:

Checkrmh将造成伤害的情况交给一个标签rmhEnjury,它是1993年的我写错了的“injury”。

这些位是在编辑器中绘制的。在游戏构建之前,我必须先构建生成它的工具:MEDITOR.S,1,254行汇编代码,通过其自身头信息标记日期,用我的1993年英语书写:

1993年2月的四天。用鼠标绘制瓷砖,在面板的CURRENT FLAG计数器上选择属性号,用PUT FLAG将其盖在单元上,标志视图会标记携带所选数字的每个单元。在写这篇文章时,我让模型运行地图编辑器并获取截图。它用现代汇编器汇编了1993年的源代码,将发售版的关卡2数据放置在编辑器预期的内存位置,然后在模拟器中启动了结果。

My 1993 map editor running in 2026, editing the real Level 2, with flag 1 (solid) selected: the waterfall scene with the solid ground marked by the flag view and the CURRENT FLAG counter reading 0001

我自己在三十三岁时的工具,编辑真正的2级关卡,标识视图开启。当前标识显示0001,实心,你可以站立的地面会被标记,而你可以穿过的装饰则不会被标记。面板上写着1994:面板的艺术图像是一个独立的位图文件,由编辑器加载,而留存下来的副本比1993年2月的代码要晚。

面板上另一个名字,乌代,是我在美索不达米亚软件的合伙人,这是我们给自己起的名字。当时他正在制作自己的游戏。我写了编辑器,供我们俩使用,但设计是我们一起商量出来的,所以一个工具可以服务于两款游戏。他的游戏从未完成。

敌人不在地图上。世界是一次存储一屏的,每屏25×20个瓷砖,每个屏幕都有一个小表格记录上面的对象。我的1993年评论解释了标记:

敌人是一行行文字:一个标记、一个帧、在其屏幕内的位置,然后是其行为。hiddenwallR-lrb 是破碎墙例程,从一个基本标签的偏移附加,其技巧和之前的箭矢投掷器相同。其后的字符是参数,其意义由该例程决定。文件中没有说明每个词代表什么,因此它找到了每帧扫描这些表格的例程,让其为字段命名,然后将所有五个关卡的每个对象转换为世界坐标,并与渲染的地图进行比对。

大多数数据文件使用文件内存储的钥匙打乱其16字节的头,这是1993年的一种防止磁盘编辑器入侵的技巧。零售加载器GAME.S 完全没有解密步骤。它把这一点当作线索:GAME.S 是在加入打乱之前编写的,所以它是较旧的文件。这个线索后来让它通过该文件内的一个扇区地图恢复丢失的双盘零售套装。

加载一个关卡的瓷砖地图,会发现每个门的位置都有空洞,但里面没有门的图块,无论是开着还是关着。一个18字节的对象记录在运行时将它们压印到地图上,是一个1×4的瓷砖列,来自一个表格:

地图数据说没有门。关卡代码说有门。三十三年来,我会告诉你地图才是真理的来源,而门只是地图数据,我从未去看过。它包含了两个事实,找到了调和它们的例程,并返回了设计方案:门在运行时由代码绘制;它们从未在编辑器里绘制到地图上。这就是为什么直接移植关卡数据会产生一个门口满是天空的塔。

在每个关卡中,颜色索引31是天空,而在瓷砖艺术中没有任何东西会绘制它。瓷砖图谱将其渲染为透明,而在它背后,铜芯会在选定的扫描线上重新绘背景色以形成垂直渐变。渐变在关卡源中作为简单的颜色列表存在。这是第二关的全部天空:

从列表中向下读,天空从浅蓝色变为接近地平线时的暖色。

渲染出的相同24个字。左边是屏幕顶部。

第一次重建错过了它,关卡看起来没问题。一种我无法命名的平面感。像素对比拒绝变为绿色,渐变又回来了。

The level-2 verification diff: white marks every differing pixel — the whole sky and the animated water, missing from the first rebuild

拒绝变绿的差异:白色是第一次重建错的每个像素,铜的天空和水色。

Amiga精灵表是平面式的(五个独立的1位位平面按平面优先条纹排列,加上透明遮罩),这一切都是通过绘制例程和原始算术推导出来的。形式如frames * width * height * 2 * 5的图表尺寸存在歧义:这个2可能意味着双宽帧,或者两行叠加,每行对应一个朝向。两种读法都匹配文件中的每个字节。它是两个朝向行;这是我在1993年的选择。

The decoded 1993 sprite sheet: two stacked rows of the same six-frame run, one row per facing direction

两个叠加的行,每行对应一个朝向,逐帧绘制,不镜像。

它标记了歧义并提出了问题。

情报判断

Aioga 编辑摘要

据摘要,作者让 Claude Fable 5 在 Claude Code 中分三步完成移植:将 34,000 行 C++ 迁入 Godot 4,处理 72,758 行无注释 68000 汇编,并把 1993 年原作作为新游戏的第二启动项嵌入。

背景分析

Babylonian Twins 于 1993 年在伊拉克巴格达的 Amiga 500 上开发,原作主要使用 68000 汇编。正文称该游戏曾于 2010 年被手工移植到 iPhone,累计下载量超过两百万。

Aioga 观点

Aioga 判断:这次案例的重点不只是把旧代码搬到新引擎,也包括重建与发售版字节一致的二进制,以及保留原作作为可启动内容;但作者明确表示移植结果仍有错误。

影响与后续

可能影响:老游戏移植可能从逐段手工重写转向结合代码分析、格式处理与人工校验的流程;但这不代表 AI 能独立保证复刻准确性,仍需要熟悉原作的人持续试玩和决策。 后续观察:应关注作者对 Godot 版本、汇编迁移过程、文件格式处理及已发现错误的进一步说明,也需要区分摘要中的移植结果与作者亲自确认的内容。

来源与版权说明

本页正文由公开来源页面提取并按原有信息整理,同时保留来源、发布时间和原文入口。版权归原作者及来源网站所有,请通过原文链接核验和阅读来源版本。

抓取通道: 摘要聚合 · 原始域名: babyloniantwins.com

来源: Hacker News 热门(buzzing.cc 中文翻译)

原文链接: 打开原始来源

Aioga 归档: 查看情报页

Content record: source-page · Updated: 2026-09-04T00:07:47.000Z

API 中转站
API RELAY · DEVELOPER INFRASTRUCTURE

API 中转站

统一接入主流 AI 模型 API,为开发、测试与生产环境提供稳定调用入口。

立即访问 api.w173.com
AIOGA SHARE POSTER

分享这篇 AI 情报

作者让 Claude Fable 5 在 Claude Code 中分三步移植其 1993 年 Amiga 游戏:34,000 行 C++ 一个晚上迁入 Godot 4,72,...

Hacker News 热门(buzzing.cc 中文翻译)2026-09-04T00:07:47.000Z
扫码打开文章详情扫码直达文章详情

Aioga 自动聚合全球 AI 动态,并保留来源信息用于核验与引用。