为什么游戏中的角色属性上限都是 99、999、9999?

图片:编辑瞎的主页 为什么游戏中的角色属性上限都是 99、999、9999?

Thinkraft,Obsessive-Compulsive-Personality-Disorde

单纯的设计选择而已。属性上限常见的设定大致分为「2^n - 1」和「999」两个流派,前者偏向以数据结构限制作为取值范围,后者偏向以UI显示宽度作为取值范围,但并不绝对,也有数据和UI都支持,只是程序逻辑做限制的例子。这两个从程序实现难度和性能上讲区别也不大,拍脑门随便选即可。实际作品中,9、15、31、63、99、127、255、999、9999、65535……之类的设计我都见过。

你们都拿FC超级马里奥说事,这游戏的数值系统其实很鬼畜的。

首先说命数,实际数据类型为标准ubyte,也就是很老实地用一个字节(地址0x075A)来表示0~255的数值范围。这是正常程序员最符合直觉的实现方式。

其特别之处在于,后台的实际数值是「不算当前这一命的备用命数」,而每次过关或死命后出现黑屏显示给你看的数则是「包括当前这一命的总命数」(80年代这两种表示法都很流行,街机比较喜欢用前一种方式表达残机数)。结果就要拿这个数值+1之后现场换算成两位数显示。例如实际数值是0x02,显示出来的就是3。如果这里超过0x63(99)之后就会溢出造成显示出错。

金币的数据结构则是令人匪夷所思的所见即所得设计。屏幕上显示的金币数量(00~99),十位数和个位数分别用0x07ED和0x07EE两个字节控制,这两个字节不仅决定了显示内容(CHR地址),而且还直接参与游戏逻辑计算(大概意思就是吃金币时先检查个位数,<9就+1,>=9就归零且继续对十位数进行该计算)。如果你强行修改这两个地址的值,例如改成0x04、0x09,屏幕上就会显示你有49个金币。然后你再吃一个金币,就会变成50。如果你把个位数锁成超出范围的值,例如0x0A,则个位数会根据游戏CHR码表显示对应的字母、符号之类的内容,并且每次吃金币十位数都会相应进位。

每100金币奖命的逻辑跟这个显示无关,而是单独另有一个字节控制,地址0x075E。每当吃到金币的时候,这个地址的值也会跟着+1,随后立刻检查它是否==0x64(十进制100),如果满足条件就执行奖命同时清零。这个地址和上面说的显示用的两个地址是分开独立运作的,注意,游戏程序并不是一切以后台这个隐藏数值为准、显示时换算成十进制;而是两者独立运作,分别累加。

类似地,该作中的剩余时间数字也并没有像正常做法那样使用标准byte/ubyte记录,而是花了三个字节分别表示百位、十位、个位,地址0x07F8、0x07F9、0x07FA,并且直接参与计算。如果你把前两个数值锁成0x00、0x00就会造成开局瞬间秒杀。

分数同理,采用了0x07DD到0x07E2的六个字节分别来表示六位数字(另外0x07D7到0x07DC则是高分记录),并且直接参与计算。稍有不同的是这六位数字并不是从十万位到个位,而是从百万位到十位,其中百万位为0时隐藏不画。至于个位数,呵呵,它根本就不是分数系统的一部分。个位那个0是直接画上去的图而已。

一个1985年的游戏,为了表示一个百万级的数字,可以随手浪费6个字节(虽然8位CPU这样处理或许反而更方便),所以问题根本不在省内存上。机器内存容量是定死的,不用白不用。至于后来出现有存档的游戏,可利用空间也到了KB级别,也无所谓255还是999了。

至于为什么「很多游戏」选择使用「999」类而不是「2^n - 1」类数字作为数值上限设计,这就没法回答了,具体到每个游戏上设计师都可能有自己的想法。在我看来这两个没有孰优孰劣,选哪个都可以有很多原因也可以没有原因