古惑狼游戏封面英文原文:二十五年前,游戏开发者是如何将整个游戏打包到这么小的内存中的?25年前,开发人员如何将游戏装入如此小的内存中?在Quora上,这个问题已经有50万人阅读,DaveBaggett对问题的回答也获得了超过6000个赞,其中不乏一些游戏高手。问题描述家庭游戏系统软件使用64K~128K的磁卡(卡),但可以提供多种图形、鬼影和声音,可以连续玩几个小时。游戏系统似乎提供了大量的功能(功能函数、库、硬件加速和图形指令等),大量的图片、音乐和音效、动画效果、游戏算法可以放在这么小的地方存储空间,多么令人惊讶,更何况是25年前!上述存储大小目前看来相当于一个中等分辨率的压缩JPEG文件——只是一张图片。我很好奇那个年代的软件开发是什么样子的。我坚信,那时候的开发者肯定没有编写开源软件的所谓协同开发环境,更没有一个软件开发可以获得巨大经济回报的时代。我很好奇那个时代的开发者是基于什么知识、技术、思想或见解来完成这样的开发。是否有可能某些想法已丢失或未记录?电子游戏种类繁多,数以百万计的人花费了数百小时来享受它们,更不用说开发游戏的如此高效的方式了——这显然是一项壮举。这种效率让我想起了录制的音乐演示。结合这些,我想提出以下问题:如何更好地理解计算机科学的原理和技术的使用,例如,如何编码一个64K的demo。这个问题侧重于当时的专业知识:为什么当时的开发人员如此成功?他们使用了哪些丢失的技术、解决方案或算法技巧?DaveBaggett的回答以下是1990年代后期的一则相关轶事。当时,我和AndyGavin正在为PS1共同编写游戏CrashBandicoot。当时,RAM仍然是主要问题。PS1只有2MB内存,但我们不得不做一些疯狂的事情来让游戏适合硬件。我们的游戏数据大小约为10MB,因此我们必须动态调入和调出页面,我们没有出现任何故障,尽管帧率会因加载延迟而降至30Hz。它之所以有效,是因为Andy编写了一个令人难以置信的分页系统,该系统将64K数据页换出作为CrashBandicoot的数据遍历级别。这就是当时的“全栈”能力。在这个分页系统中,运行了从高级内存管理到操作码级别的直接内存访问系统(DMA)的所有代码。Andy甚至控制了CD-ROM磁盘上字节的物理布局,这样即使磁盘以300KB/s的速度运行,PS1仍然可以在游戏执行过程中的某个时刻加载数据。我当时主要负责写一个打包工具。这个工具的作用是将声音、图形图像、小动物声音控制代码(译者注:lisp控制代码)等资源文件打包成64K的数据页,塞进安迪的系统中。(顺便说一句,这个问题——将任意大小的对象打包到固定大小的数据页中,产生数据包——是NP完全的,所以它看起来在合理的时间或线性复杂度内解决是不可能的。)但是,有时算法不合适,我的打包工具用了各种算法(比如bestfit,bestfit(first-fit,best-fit)等),就是为了找到最好的打包方案,包括使用类似于模拟退火中使用的梯度下降过程。基本上,我写了一堆不同的打包策略,都试过了,然后选择了最好的。使用像这样的随机引导搜索的问题是你永远不知道你是否会再次得到相同的结果。有些CrashBandicoot关卡只能“偶然”随机打包,并放入允许的最大页数(我印象中是21页)。这意味着一旦你打包这个级别,可能会更改海龟的代码,你将再也找不到这个21页的包。有几次美工改变了一些东西,它破坏了当前的页数,所以我们不得不半随机地改变一些东西,直到打包器可以再次找到可用的包。我必须在凌晨3点向这位固执的艺术家解释。现在回想起来,迄今为止最好的部分,也是当时最糟糕的部分,是调整核心C/汇编代码。我们距离“最终测试版”的发布截止日期只有几天的时间,而这几天是我们在假期期间发布游戏的唯一机会,以免我们浪费了一整年的时间。当时我们在对C语言代码进行随机排列semanticlyidenticalbutsyntacticallydifferentmanifestations(语义相同但句法不同的表现形式),希望编译器能生成200字节、125字节、50字的section后面的代码小于8个字节。作为当时用于排列的方法“for(i=0;i
