Press "Enter" to skip to content

Posts tagged as “game”

轮回的载体:从红白机到NS2“Key卡”风波,看游戏介质的四十年战争

前言:历史总是在押韵

前段时间,关于任天堂NS2“Key卡”模式的传闻闹得沸沸扬扬。所谓的Key卡,即实体卡带中不再包含完整游戏数据,仅存储启动授权(License Key)和少量引导文件,核心内容需通过网络下载。

玩家的愤怒可以理解——“我买了实体盘,却只买了个寂寞?”但如果你是经历过90年代PC游戏黄金期的老玩家,或许会会心一笑:这不就是当年的“Play Disc”吗?早在《星际争霸1》或《暗黑破坏神2》时代,我们不就是把游戏最大化安装到硬盘,CD光盘仅用来过DRM验证和播放CD音轨吗?

从FC的卡带到PS的光盘,再到如今PS5的SSD,游戏介质的演变史,本质上是一场存储成本读取速度之间的永恒博弈。今天,我们就来扒一扒这本跨越40年的技术账。


第一章 硅基的浪漫:卡带的黄金时代 (FC/SFC/GB/N64)

在那个电子游戏的洪荒年代,ROM卡带(Cartridge)是绝对的王者。

1.1 毫秒级的快乐

FC(红白机)时代的卡带,与其说是存储介质,不如说是主机硬件的一部分。当你插入《魂斗罗》时,你实际上是把额外的电路板插在了主板的总线上。

  • 优点: 极致的读取速度。由于直接与CPU总线寻址,读取几乎是零延迟。没有“Loading”界面是那个时代最被低估的幸福。
  • 黑科技: 厂商可以在卡带里塞入特殊芯片。比如任天堂在SFC《星际火狐》卡带里塞了Super FX芯片来辅助3D运算,这在光盘时代是无法想象的。

1.2 昂贵的代价

卡带的致命伤在于容量成本(Mask ROM)。

  • 容量瓶颈: FC游戏通常只有几百KB(比如《超级马里奥兄弟》只有40KB)。到了N64末期,最大容量也不过64MB(512Mbit)。
  • 价格高昂: 90年代一张正版卡带动辄400-600元人民币(按当时汇率),因为内存颗粒真的很贵。

第二章 光学的革命:容量的爆发与读盘的噩梦 (PS1/SS/PS2)

1994年,索尼PS1横空出世,通过CD-ROM彻底改变了游戏界。这场变革的核心逻辑是:用速度换容量,用廉价换市场

2.1 650MB的震撼

一张CD拥有650MB-700MB的容量。这对当时最大只有几MB的卡带来说,简直是降维打击。

  • CG与音质: 因为有了海量空间,《最终幻想7》才能塞入大量的预渲染CG动画和高音质音乐。
  • 成本骤降: 压制一张光盘的成本不到1美元,而生产一盘卡带可能需要15-20美元。这让发行商赚得盆满钵满。

2.2 “Loading…”的恐惧

光盘带来了巨大的副作用:寻道时间(Seek Time)。光头要在盘面上移动读取数据,导致了漫长的读盘时间。

  • PS1/PS2时代: 2倍速、4倍速光驱的读取速度仅为300KB/s – 600KB/s。
  • 噪音与磨损: 飞速旋转的电机声和划伤的光盘成为了玩家的新烦恼。

第三章 混沌年代:混合模式与HDD的介入 (PS3/Xbox360/PC)

进入高清时代,DVD的容量(4.7GB/8.5GB)开始捉襟见肘,蓝光(Blu-ray)登场。但此时,光驱读取速度已经跟不上游戏数据量的膨胀了。

3.1 90年代的PC启示录(Key CD模式)

由于早期CD光驱速度慢(1x/2x),而硬盘速度快,当时诞生了“最大化安装”。

  • 机制: 游戏逻辑、贴图全部Copy到硬盘。
  • 光盘作用:
    1. Key(钥匙): 防盗版验证。
    2. CD Audio: 直接利用光驱播放CD音轨(节省CPU资源)。这就是如今“Key卡”模式的雏形。

3.2 强制安装时代

到了PS3和Xbox 360后期,以及PS4/PS5全世代,光盘实际上已经不再作为运行介质了。

  • 现状: 当你把PS5的《战神:诸神黄昏》光盘插入机器,光驱会全速运转将数据“Copy”到SSD中。之后玩游戏时,光盘仅在启动时转动几秒钟验证License,随后便停止。
  • 本质: 现代光盘,就是一张存满离线安装包的Key卡

第四章 数据对比:卡带 vs 光盘 vs SSD

为了直观展示介质的优缺点,我们来看一张详细的参数对比表:

世代/平台核心介质典型容量最大读取速度生产成本玩家体验关键点
FC (8-bit)Cartridge40KB – 1MB极快 (总线级)插卡即玩,无加载,怕震动
SFC (16-bit)Cartridge512KB – 6MB极快极高特殊芯片加持,价格昂贵
PS1 (32-bit)CD-ROM650MB – 700MB~300KB/s (2x)极低海量CG,但读盘慢,易划伤
PS2 (128-bit)DVD-ROM4.7GB – 8.5GB~5MB/s (4x)依然受困于光驱速度
PS3Blu-ray25GB – 50GB~9MB/s (2x)强制安装开始普及
SwitchGame Card4GB – 32GB~100MB/s高 (专利费)回归卡带,便携,防苦味涂层
PS5UHD BD100GB仅作为安装盘SSD速度(5.5GB/s)接管一切
NS2Game Card + Card (Key)4GB – 64GB~800MB/s低 (如仅含Key)实体收藏 + 数字下载

第五章 现代困局:摩尔定律下的存储危机

为什么NS2要搞“Key卡”?为什么3A大作越来越大?

5.1 3A游戏的体积膨胀

随着4K材质、无损音轨的普及,游戏体积呈指数级增长。

  • 《使命召唤》系列常年霸占150GB+。
  • 《NBA 2K》系列动辄120GB。

5.2 Switch的“卡带税”痛点

任天堂Switch重新启用卡带(闪存介质),虽然读取速度(约100MB/s)远快于光盘,但面临巨大的成本压力。

  • 成本阶梯: 8GB卡带很便宜,16GB尚可,32GB成本陡增,64GB卡带更是天价。
  • 厂商对策: 为了省钱,很多第三方厂商(如2K Games)发行实体版时,只用8GB卡带装个开头,剩下50GB让你回家自己下载。这其实已经是“半Key卡”模式了。

第六章 未来展望:Key卡作为收藏,下载作为常态

对于未来的游戏发行“Key卡收藏 + 游戏下载”,不仅是趋势,更是解决“实体党”与“数字化”矛盾的最优解。

6.1 为什么这种模式是必然?

  1. 解决首日补丁(Day 1 Patch)悖论:现在的实体光盘,里面刻录的是版本1.0。但往往游戏发售当天就有几十GB的1.01补丁。那张光盘里的数据在发售那一刻其实已经“过期”了。既然都要下载,何必执着于把完整数据压在盘里?
  2. 环保与成本的双赢:生产高容量闪存卡(如64GB/128GB)需要消耗大量半导体资源。如果实体卡只是一张精美的、带有NFC验证芯片的塑料片(类似Switch卡带,但容量极小),成本将大幅降低。厂商省钱,玩家买卡带也不用因为“卡带税”而比数字版贵。
  3. 满足收藏癖(Shelf Value):玩家(包括我)买实体版,很多时候是为了那个盒子,为了把它摆在书架上。Key卡模式保留了封面、包装盒、说明书(如果有的话)以及一张可以拿在手里的“凭证”。

6.2 理想的“Key卡”形态

我设想中完美的NS2实体卡应该具备以下特征:

  • 只读存储区(几百MB): 存储游戏的基础引导程序、离线授权Key、精美的电子说明书、原声OST。
  • 写入存储区(可选): 允许玩家将自己的存档回写到卡带中(就像当年的记忆卡一样)。这样带着卡带去朋友家,既带了授权,也带了存档。
  • 即插即得: 插入卡带,系统自动触发下载。

6.3 潜在的风险与担忧

当然,这种模式也有弊端,主要是游戏保存(Preservation)问题。

  • 服务器关停: 20年后,当任天堂关闭了下载服务器,这张Key卡还能用吗?
  • 解决方案: 法律应规定,当官方服务器关闭时,Key卡应被解锁为“离线安装包”的解压密钥,允许玩家从第三方归档库合法安装。

结语:从“拥有数据”到“拥有权利”

从红白机时代手里沉甸甸的卡带,到未来可能只是一张轻飘飘的“Key卡”,我们“拥有”游戏的方式正在改变。

曾经,我们拥有的是数据的载体;

未来,我们拥有的将是数据的访问权和一份实体化的纪念品。

NS2推行Key卡模式,只要能把省下的卡带成本让利给玩家,并做好网络基础设施建设,这或许并不是坏事。毕竟,对于真正的玩家来说,最重要的永远是屏幕亮起那一刻,那是通往另一个世界的钥匙——无论这把钥匙是金做的,还是数据做的。

附录 关于读盘速度

回顾PS1和PS2时代,读盘速度慢通常由两个核心原因造成:

  1. 光驱本身的物理限制(PS1是2倍速CD,PS2是4倍速DVD),寻道时间(Seek Time)长。
  2. 内存限制(PS1只有2MB主内存),导致无法一次性读取大量数据,必须频繁访问光盘。

以下是几个教科书级别的“读盘地狱”案例,包含具体数据和体验描述:

一、 PS1时代:2倍速光驱的噩梦

PS1时代最痛苦的往往不是RPG(因为切图慢大家还能忍),而是从街机或卡带移植的动作/格斗游戏。这类游戏在街机/卡带上是零延迟的,到了光盘上就变成了灾难。

1. 《合金弹头 1》 (Metal Slug) – PS1版

  • 现象: 切屏即读盘。
  • 数据: 每次关卡内切换场景(哪怕只是从这头走到那头),都需要 5-10秒 的“Now Loading”。
  • 体验: 在街机上行云流水的动作射击体验被切得支离破碎。你刚打完一波兵,想往前冲,屏幕黑了,右下角出现Loading字样。原本15分钟能通关的游戏,在PS1上因为读盘硬生生拖到了25分钟。
  • 原因: PS1内存仅2MB,存不下那么多精致的2D像素动画帧,必须打一段读一段。

2. 《拳皇 97》 (The King of Fighters ’97) – PS1版

  • 现象: 回合制读盘。
  • 数据: 选人界面进入战斗需要 15秒+。最要命的是,每打赢一个人,换下一个对手上场时,需要读盘 10-12秒
  • 体验: 3V3的对决,如果你把对面一穿三,你要看三次读盘画面。加上开场的Loading,一场几分钟的格斗,有一分半钟在看黑屏。
  • 对比: 土星(SS)版因为有额外的4MB加速卡(扩充内存),读盘几乎不可感;而PS1版简直是折磨。

3. 《时空之轮》 (Chrono Trigger) – PS1版 (收录于FF Chronicles)

  • 现象: 最著名的“反向移植”案例。
  • 数据:
    • 进入战斗: SFC版是瞬间进入;PS1版屏幕会黑并停顿 4-6秒 才能切入战斗画面。
    • 打开菜单: 按下菜单键,需要等 3-5秒 菜单才会弹出来。
  • 体验: 这是一个在SFC卡带上“秒开”的游戏。到了机能更强的PS1上,因为光盘寻道机制,连打开背包都要读盘。这种高频次、短时间的卡顿比一次性长读取更搞心态。

二、 PS2时代:大容量带来的“长考”

PS2虽然升级到了DVD,但游戏素材(纹理、模型、音频)的体积增长远超光驱速度的提升(仅4倍速)。

1. 《古惑狼:由于科尔特斯的愤怒》 (Crash Bandicoot: The Wrath of Cortex) – 初版

  • 现象: PS2初期最著名的“读盘王”。
  • 数据: 进入一个普通关卡需要 40秒 到 60秒
  • 体验: 在这将近一分钟的时间里,你只能看着主角Crash在屏幕中间做自由落体运动。考虑到这是一款动作游戏,玩家经常会死,死一次就要重新读盘或者读CheckPoint(也要很久),这种挫败感是毁灭性的。
  • 后续: 由于骂声太大,后来发行的“Greatest Hits”廉价版优化了文件结构,将读盘时间缩短到了20多秒。

2. 《模拟人生》 (The Sims) – PS2版

  • 现象: PC移植带来的水土不服。
  • 数据: 启动游戏进入家庭可能需要 2-3分钟。如果在游戏中去邻居家串门,或者切换到“购买/建造模式”,经常需要等待 30-45秒
  • 体验: 这个游戏本来就需要频繁切换模式。由于读盘太慢,很多玩家干脆不装修房子了,或者不敢出门社交,硬生生玩成了“宅男模拟器”。

3. 《WWE SmackDown! vs. Raw 2006》

  • 现象: 漫长的赛前准备。
  • 数据: 这种体育类游戏,由于要加载几名摔角手的高精度模型、出场动画、专属音乐、场馆观众。一场比赛开始前的总读盘时间(包含出场)往往超过 1分半钟
  • 体验: loading条也是出了名的慢,经常卡在90%不动,让人怀疑死机了。

4. 《侠盗猎车手:圣安地列斯》 (GTA: SA) – 地图流送问题

  • 现象: 这是一个特殊的例子,它没有Loading画面,但它读盘慢到跟不上游戏速度
  • 数据/体验: 当你驾驶战斗机(Hydra)在低空全速飞行时,PS2的光驱读盘速度跟不上地图数据的加载速度。
  • 结果: 你会飞进一片模糊的色块中,或者直接撞上一栋还没加载出来的透明大楼。这就是典型的光驱读取瓶颈(Streaming Latency)。

三、 数据总结表:为什么卡带/SSD是神

我们可以对比一下这些操作在不同介质上的大致耗时:

操作场景FC/SFC/N64 (卡带)PS1/PS2 (光盘)PS5/XSX (NVMe SSD)
打开系统菜单< 0.1秒 (瞬间)3 – 5秒 (甚至更久)< 0.1秒
进入战斗/关卡< 1秒15 – 60秒1 – 3秒
死亡重开< 0.5秒10 – 40秒< 1秒
高速移动中加载地图无感贴图模糊/物体消失无感

光盘时代虽然带来了大容量和多媒体盛宴,但在“即时反馈”这一游戏核心体验上,实际上是倒退的。

逆转裁判 Ace Attorney | GBA遮罩 Overlay | RG556

最近在玩《逆转裁判》,在iOS上买了合集 Ace Attorney Trilogy(花了我$24.99大洋呢,今天降到$14.99了)。虽然画面重绘过了,高清了不少,官方中文版也加入了中文语音(异议!),但本人不太喜欢搓玻璃,所以又开始倒腾模拟器,手上有周哥的RG35XX HRG556(悄悄说RG34XX还在路上,不过它就不用遮罩了)。给556做了个遮罩(其实就是张图片,PS水平实在有限),应该也适用于其他1920×1080,GBA 6倍点对点的屏幕,只考虑掌机,所以没有加按钮,喜欢的可以自行拿走。

效果预览

截屏
实机拍摄

Update: 2/24/2025

1-3终于全部通关了,最后一个故事太精彩了!送上几幅截屏,给这段旅程画上一个顿号。

罐子其实在真宵小时候就被打破过~
全家福
三人组

花花酱 LeetCode 1872. Stone Game VIII

Alice and Bob take turns playing a game, with Alice starting first.

There are n stones arranged in a row. On each player’s turn, while the number of stones is more than one, they will do the following:

  1. Choose an integer x > 1, and remove the leftmost x stones from the row.
  2. Add the sum of the removed stones’ values to the player’s score.
  3. Place a new stone, whose value is equal to that sum, on the left side of the row.

The game stops when only one stone is left in the row.

The score difference between Alice and Bob is (Alice's score - Bob's score). Alice’s goal is to maximize the score difference, and Bob’s goal is the minimize the score difference.

Given an integer array stones of length n where stones[i] represents the value of the ith stone from the left, return the score difference between Alice and Bob if they both play optimally.

Example 1:

Input: stones = [-1,2,-3,4,-5]
Output: 5
Explanation:
- Alice removes the first 4 stones, adds (-1) + 2 + (-3) + 4 = 2 to her score, and places a stone of
  value 2 on the left. stones = [2,-5].
- Bob removes the first 2 stones, adds 2 + (-5) = -3 to his score, and places a stone of value -3 on
  the left. stones = [-3].
The difference between their scores is 2 - (-3) = 5.

Example 2:

Input: stones = [7,-6,5,10,5,-2,-6]
Output: 13
Explanation:
- Alice removes all stones, adds 7 + (-6) + 5 + 10 + 5 + (-2) + (-6) = 13 to her score, and places a
  stone of value 13 on the left. stones = [13].
The difference between their scores is 13 - 0 = 13.

Example 3:

Input: stones = [-10,-12]
Output: -22
Explanation:
- Alice can only make one move, which is to remove both stones. She adds (-10) + (-12) = -22 to her
  score and places a stone of value -22 on the left. stones = [-22].
The difference between their scores is (-22) - 0 = -22.

Constraints:

  • n == stones.length
  • 2 <= n <= 105
  • -104 <= stones[i] <= 104

Solution: Prefix Sum + DP

Note: Naive DP (min-max) takes O(n2) which leads to TLE. The key of this problem is that each player takes k stones, but put their sum back as a new stone, so you can assume all the original stones are still there, but opponent has to start from the k+1 th stone.

Let dp[i] denote the max score diff that current player can achieve by taking stones[0~i] (or equivalent)

dp[n-1] = sum(A[0~n-1]) // Alice takes all the stones.
dp[n-2] = sum(A[0~n-2]) – (A[n-1] + sum(A[0~n-2])) = sum(A[0~n-2]) – dp[n-1] // Alice takes n-1 stones, Bob take the last one (A[n-1]) + put-back-stone.
dp[n-3] = sum(A[0~n-3]) – max(dp[n-2], dp[n-1]) // Alice takes n-2 stones, Bob has two options (takes n-1 stones or takes n stones)

dp[0] = A[0] – max(dp[n-1], dp[n-1], …, dp[1]) // Alice takes the first stone, Bob has n-1 options.

Time complexity: O(n)
Space complexity: O(1)

C++

花花酱 LeetCode 1690. Stone Game VII

Alice and Bob take turns playing a game, with Alice starting first.

There are n stones arranged in a row. On each player’s turn, they can remove either the leftmost stone or the rightmost stone from the row and receive points equal to the sum of the remaining stones’ values in the row. The winner is the one with the higher score when there are no stones left to remove.

Bob found that he will always lose this game (poor Bob, he always loses), so he decided to minimize the score’s difference. Alice’s goal is to maximize the difference in the score.

Given an array of integers stones where stones[i] represents the value of the ith stone from the left, return the difference in Alice and Bob’s score if they both play optimally.

Example 1:

Input: stones = [5,3,1,4,2]
Output: 6
Explanation: 
- Alice removes 2 and gets 5 + 3 + 1 + 4 = 13 points. Alice = 13, Bob = 0, stones = [5,3,1,4].
- Bob removes 5 and gets 3 + 1 + 4 = 8 points. Alice = 13, Bob = 8, stones = [3,1,4].
- Alice removes 3 and gets 1 + 4 = 5 points. Alice = 18, Bob = 8, stones = [1,4].
- Bob removes 1 and gets 4 points. Alice = 18, Bob = 12, stones = [4].
- Alice removes 4 and gets 0 points. Alice = 18, Bob = 12, stones = [].
The score difference is 18 - 12 = 6.

Example 2:

Input: stones = [7,90,5,1,100,10,10,2]
Output: 122

Constraints:

  • n == stones.length
  • 2 <= n <= 1000
  • 1 <= stones[i] <= 1000

Solution: MinMax + DP

For a sub game of stones[l~r] game(l, r), we have two choices:
Remove the left one: sum(stones[l + 1 ~ r]) – game(l + 1, r)
Remove the right one: sum(stones[l ~ r – 1]) – game(l, r – 1)
And take the best choice.

Time complexity: O(n^2)
Space complexity: O(n^2)

C++/Top Down

C++/Bottom-Up

Python3

Related Problems

花花酱 LeetCode 1686. Stone Game VI

Alice and Bob take turns playing a game, with Alice starting first.

There are n stones in a pile. On each player’s turn, they can remove a stone from the pile and receive points based on the stone’s value. Alice and Bob may value the stones differently.

You are given two integer arrays of length naliceValues and bobValues. Each aliceValues[i] and bobValues[i] represents how Alice and Bob, respectively, value the ith stone.

The winner is the person with the most points after all the stones are chosen. If both players have the same amount of points, the game results in a draw. Both players will play optimally.

Determine the result of the game, and:

  • If Alice wins, return 1.
  • If Bob wins, return -1.
  • If the game results in a draw, return 0.

Example 1:

Input: aliceValues = [1,3], bobValues = [2,1]
Output: 1
Explanation:
If Alice takes stone 1 (0-indexed) first, Alice will receive 3 points.
Bob can only choose stone 0, and will only receive 2 points.
Alice wins.

Example 2:

Input: aliceValues = [1,2], bobValues = [3,1]
Output: 0
Explanation:
If Alice takes stone 0, and Bob takes stone 1, they will both have 1 point.
Draw.

Example 3:

Input: aliceValues = [2,4,3], bobValues = [1,6,7]
Output: -1
Explanation:
Regardless of how Alice plays, Bob will be able to have more points than Alice.
For example, if Alice takes stone 1, Bob can take stone 2, and Alice takes stone 0, Alice will have 6 points to Bob's 7.
Bob wins.

Constraints:

  • n == aliceValues.length == bobValues.length
  • 1 <= n <= 105
  • 1 <= aliceValues[i], bobValues[i] <= 100

Solution: Greedy

Sort by the sum of stone values.

Time complexity: O(nlogn)
Space complexity: O(n)

C++