← 返回信息流
AI 资讯Hacker News·2 小时前

经典弹球大战登陆Commodore 64

原标题:Pong Wars on the Commodore 64

速览

Pong Wars是一款基于经典乒乓球玩法的游戏,近日被移植到Commodore 64平台上运行。该移植展现了复古硬件上的游戏开发技巧,吸引怀旧爱好者关注。不过这一资讯更多属于复古游戏与编程趣味,与当前AI技术趋势无关。

AI 深度解读

背景

2024年初,一篇关于在Commodore 64上重现“Pong Wars”的帖子在Hacker News上引发关注。作者Imran Nazar(Two9A)在浏览Mastodon时,看到Koen van Gilst用JavaScript复刻了“Pong Wars”效果——一个关于“白天”球和“黑夜”球永恒对抗的动画,通过碰撞反转对方区域的颜色。该动画在网络上广受欢迎,拥有数千点赞。作者由此产生一个念头:既然van Gilst能在JavaScript中复现,那么作为Commodore 64爱好者,是否也能在老旧的8位计算机上实现同样的动画?尽管作者长期对C64有浓厚兴趣,但此前从未为其编写过任何实质性的汇编代码。本文记录了作者在C64上实现这一效果的技术探索过程,从项目规划、硬件特性利用到具体代码实现,揭示了在有限硬件条件下完成复杂图形动画的挑战与解决方案。

核心内容

项目目标是模拟两个球(“白天”球和“黑夜”球)在20×20的方块区域(blockfield)内平滑运动:球沿直线移动,碰到边界会反弹;同时球碰到某个方块时,该方块的颜色会反转(从白变黑或从黑变白)。整个动画需要在Commodore 64的标准文本模式下运行,并尽可能不影响其他可能运行的程序(如BASIC解释器)。

硬件特性与时机:C64的视频输出采用CRT,每帧视频输出后有一小段垂直消隐期(vertical blanking period),在此期间视频芯片不占用内存访问。作者计划将动画所需的全部计算限制在消隐期内完成,以避免干扰帧渲染期间的其他进程(如BASIC运行)。

利用中断挂钩:C64的BASIC解释器提供了“光栅中断”(Raster interrupt)机制,允许在每帧底部执行自定义代码,同时保持BASIC运行。作者利用这一挂钩来执行主循环代码。

初始化步骤

  1. 清屏并设置字符:C64默认文本模式为40×25字符(每个字符8×8像素)。屏幕RAM起始于内存位置$0400,颜色RAM位于$D800。作者使用一个简单的循环(1024字节)将屏幕填充为空格字符(32),并将指针指向屏幕左上角。BLOCKPTR存储于未被BASIC和Kernal ROM使用的内存区域(根据STA演示组Joe Forster的C64内存映射)。

  2. 绘制20×20方块区域:要将方块区域居中显示在屏幕上,需起始于第1行(向下偏移1行)和第10列(向左偏移9个字符,因为使用递减循环可节省比较指令)。作者选择使用反向视频的空格字符(字符160)作为纯前景色方块(白色),背景色为C64默认蓝色。通过嵌套循环:外层循环控制20行,内层循环写入20个字符(从19递减到0),每行完成后指针增加40(跳过后面的20个空白列)。

  3. 双缓冲颜色RAM:作者采用双缓冲技术简化碰撞计算。内部缓冲区BLOCKBUF(位于$CE00,512字节未使用RAM)保存400个黑白值(0或1),每帧渲染到颜色RAM。初始化时,缓冲区被设置为20行,每行前10个为黑色(0),后10个为白色(1),通过交替写入10个连续值并交换0/1状态实现。处理16位指针加法时,累加器值被压入栈保存,恢复后再通过异或1切换颜色。

  4. 精灵设置:需要为两个平滑移动的球创建8×8像素的精灵图形。作者使用在线像素圆生成器(Donat Studios)生成8×8的圆形精灵数据。在C64上,精灵图形数据需加载到特定内存区域,并配置精灵指针。

主循环逻辑(未在原文中详细展示,但根据上下文可推断):每帧通过光栅中断触发主例程,更新两个球的位置,检测与边界、方块的碰撞,反转被碰方块的颜色,并将内部缓冲区渲染到颜色RAM。

关键要点

  • 技术挑战:作者此前从未为C64编写过汇编代码,整个项目是边学边做。在仅有1MHz CPU、39KB可用RAM(部分被BASIC占用)的8位机器上实现实时动画,需精心优化代码。
  • 关键优化
    • 所有计算限制在垂直消隐期内完成,避免干扰帧渲染。
    • 使用双缓冲技术:内部400字节缓冲区存储方块颜色状态,每帧整体渲染到颜色RAM,简化碰撞更新逻辑。
    • 利用位置指针递减循环(从19到0)避免循环内的比较指令,节省时钟周期。
    • 16位指针加法使用压栈/出栈保存累加器,并通过EOR指令快速切换颜色值(0↔1)。
  • 内存布局利用
    • 屏幕RAM($0400)和颜色RAM($D800)的固定位置被充分利用。
    • 使用BASIC未使用的内存区域($03-$04段中的两个字节)作为工作指针。
    • 内部缓冲区位于$CE00,为512字节未使用RAM,足够存放400个颜色值。
  • 精灵图形:采用8×8像素圆生成器生成球体精灵,充分利用C64的精灵硬件实现平滑移动(每个精灵独立位置、颜色、大小)。
  • 光栅中断挂钩:利用BASIC提供的每帧底部中断,植入自定义代码,同时保持BASIC继续运行。

意义与影响

这篇技术帖不仅展示了在资源受限的8位平台上重现现代Web动画的可行性,还深入挖掘了Commodore 64的底层编程技巧。作者从零开始学习汇编,最终实现一个完整的动态图形演示,为复古计算爱好者提供了一个极佳的学习案例。文章详细记录了每一步的硬件知识、内存映射、优化策略和代码实现,体现了对C64架构的深刻理解。同时,这种“反向复刻”现象(从现代JavaScript倒退至1980年代硬件)凸显了复古计算社区的创造力:即便硬件性能有限,通过精巧的编程仍能创造出令人惊叹的视觉效果。该项目也启发了其他开发者尝试在更多老旧平台上移植此类动画,推动了C64汇编编程的复兴与知识传承。

查看原文 →imrannazar.com