1980 年 5 月 22 日事件时间
造物立场:共识双轨影响量级 5/5

《吃豆人》的心理设计:幽灵 AI 与可控恐惧的精密工程

四段寻路逻辑、两种行为模式、一个 8 位计数器的边界——性格化敌人的起点

史话编委会 · 设计组21 分钟5.1k 阅读
《吃豆人》的心理设计:幽灵 AI 与可控恐惧的精密工程 — 游戏史话 · 玩法革命

《吃豆人》的心理设计:幽灵 AI 与可控恐惧的精密工程

一个反直觉的事实:四个幽灵共用同一套 AI

大多数玩家会告诉你,《吃豆人》里有四个「性格」不同的幽灵:红色的 Blinky 穷追不舍,粉色的 Pinky 喜欢包抄,青色的 Inky 行为诡异,橙色的 Clyde 时而追击时而摸鱼。

这个描述是准确的。但如果你打开 1980 年那块街机基板的代码,会发现一个反直觉的事实:四个幽灵运行的是同一套寻路逻辑。它们的移动规则完全一致,唯一的差别只有一个函数——目标格怎么算

这可能是游戏史上性价比最高的一次设计。岩谷彻和他的团队没有写四套 AI,他们写了一套 AI 和四个参数,然后从中长出了四个被全世界记住了四十多年的角色。

本文完整还原这套系统:共用的移动规则、四种目标格算法、散步与追踪的切换周期、以及那个著名的第 256 关溢出。最后给出一份可以直接迁移到现代项目的行为状态机骨架——因为这套结构在今天依然是「让敌人有性格」这个需求的最优解。

关于本文的技术细节:下述算法基于对原始街机 ROM 的社区逆向工程成果(主要参考 Jamey Pittman 的《The Pac-Man Dossier》),描述的是 Namco 原版行为。北美 Midway 版本在部分参数上有差异,各类家用移植与复刻版则普遍简化了这套逻辑——你在手机小游戏里遇到的幽灵,多半没有下面这些东西。

第一层:所有幽灵共用的移动规则

在讨论差异之前,先把共同点说清楚。四个幽灵遵守完全相同的三条规则。

规则一:只在路口做决策

幽灵不是每帧都在思考。它们沿着当前方向持续移动,只有在进入一个路口格(tile)时才做一次转向决策。这个设计有三重收益:

  • 性能:1980 年的硬件负担不起每帧四次寻路计算
  • 可读性:玩家能观察到稳定的移动直线,从而预测幽灵的路径
  • 手感:决策点稀疏意味着玩家的规避操作有明确的时间窗口

规则二:贪心选择 + 禁止掉头

在路口,幽灵的决策算法是纯粹的一步贪心

在路口时:
  候选方向 = 所有可通行方向 − 来路方向     // 禁止 180° 掉头
  对每个候选方向:
      下一格 = 当前格 + 该方向
      距离 = 欧几里得距离²(下一格, 目标格)  // 平方距离,免开方
  选择距离最小的方向
  若有并列,按 上 → 左 → 下 → 右 的固定优先级裁决

注意这里没有任何路径搜索——没有 A*,没有 BFS,没有回溯。幽灵完全不知道迷宫的拓扑结构,它只知道「哪个方向能让我离目标点的直线距离更近」。

这个选择是 1980 年硬件条件下的必然,但它意外地成为了整个设计的关键:贪心算法会犯错。当目标点在墙的另一侧时,幽灵会径直撞向墙壁然后被迫绕路。正是这些「愚蠢」的瞬间,构成了玩家赖以生存的空隙。一个用 A* 寻路的幽灵会是完美的、无趣的、也是无法被战胜的。

设计提取:敌人 AI 的可玩性下限不来自它有多聪明,而来自它的失败模式是否可被玩家理解和利用。贪心算法的失败是几何性的、可预测的——玩家能学会「把幽灵引到墙后」。这种可学习的缺陷,比任何难度曲线都更能制造掌控感。

规则三:固定的优先级裁决

并列时按「上、左、下、右」裁决,这一条看似微不足道,实际上是整个游戏可被高手完全掌握的根本原因。因为决策是确定性的:给定相同的初始状态和相同的玩家输入序列,幽灵的行为完全可复现。

这催生了《吃豆人》独有的「吃分路线」(patterns)文化——高分玩家背下一整套固定的移动序列,能在不做任何临场反应的情况下连续通关。没有随机数,就没有运气;没有运气,就有了完美主义的空间。

第二层:四个目标格算法,四种性格

现在到了核心。所有差异都在这一个函数里。

Blinky(红):直接追踪

目标格 = 吃豆人当前所在格

最简单的一条,也是压力的主要来源。Blinky 永远朝玩家当前位置移动,玩家能感受到一条持续绷紧的追击线。

但 Blinky 还有一层额外机制,通常被称为「Cruise Elroy」:当关卡中剩余豆子数量低于某个阈值时,Blinky 的移动速度会提升到超过吃豆人的水平,并且即使在散步模式下也继续追踪玩家。阈值和加速幅度随关卡数递增。

这是一个极其精妙的节奏装置。关卡后期本应是最轻松的阶段(敌人不变,豆子变少),Cruise Elroy 把它反转成了最紧张的阶段。难度曲线在单个关卡内部就完成了一次爬升,而玩家几乎意识不到是什么让最后二十颗豆子变得如此难吃。

Pinky(粉):前方伏击

目标格 = 吃豆人当前格 + 当前朝向 × 4 格

Pinky 瞄准的不是玩家现在的位置,而是玩家四格之后可能到达的位置。效果上,它总是试图切到玩家的前方形成夹击。

与 Blinky 配合时,两者构成了一个天然的钳形:一个从后方压迫,一个在前方封堵。玩家被迫在通道中间做出转向决策——而转向恰恰会让 Pinky 的预测失效,制造出逃生窗口。两个简单规则的组合,产生了远超各自复杂度的战术层次。

著名的「向上偏移 Bug」:当吃豆人朝上时,Pinky 的目标格会同时向上 4 格和向左 4 格。这源于原始代码中一处 8 位加法的实现细节——向上方向的偏移计算复用了左移的分支。这个 Bug 从未被修复,并且成为了高手战术的一部分:朝上跑可以让 Pinky 系统性地偏离。一个实现瑕疵在四十年后变成了公认的技巧,这件事本身就值得一整篇设计论文。

Inky(青):向量延伸

锚点 = 吃豆人当前格 + 当前朝向 × 2 格
  向量 = 锚点 − Blinky 当前格
  目标格 = 锚点 + 向量          // 即以锚点为中心,把 Blinky 的位置点对称翻转

这是四者中唯一一个依赖另一个幽灵状态的算法,也是玩家永远无法直觉预测的那一个。

它的行为有一个非常反直觉的性质:当 Blinky 离玩家很远时,Inky 的目标点会被抛到迷宫的另一端,Inky 因此显得漫不经心;而当 Blinky 贴近玩家时,Inky 的目标点会收缩到玩家附近,两者形成合围。

换句话说,Inky 是一个「放大器」而不是一个「追击者」——它把 Blinky 造成的压力乘以二。玩家感受到的「这个青色的家伙行为莫名其妙」,实际上是一个二阶系统在一阶直觉下的必然观感。

Clyde(橙):距离触发的双态

若 距离(Clyde, 吃豆人) > 8 格:
      目标格 = 吃豆人当前格          // 与 Blinky 相同
  否则:
      目标格 = 左下角的散步基地格      // 掉头逃离

Clyde 会追到玩家附近,然后突然放弃并撤回角落,接着再次转身追来。玩家对它的普遍评价是「胆小」或者「摸鱼」。

但从系统角度看,Clyde 承担的是完全不同的职能:它是唯一一个会主动制造喘息的敌人。在四个幽灵全部采取压迫策略的设计里,玩家会在几十秒内被压垮。Clyde 的周期性撤退在压力曲线上打出了规律的凹陷,同时它的反复靠近又保证了这些凹陷不会变成完全安全的休息。

更重要的是,Clyde 覆盖的左下角区域恰好是迷宫中最容易形成死角的部分。它的存在让玩家不敢把那片区域当作永久避难所。一个「不称职」的敌人,实际上在做空间控制。

幽灵目标格玩家感知系统职能
Blinky玩家当前位置紧追不舍持续基础压力 + 关卡末段加速
Pinky玩家前方 4 格擅长包抄与 Blinky 形成钳形,逼迫转向
Inky关于玩家前方 2 格,Blinky 的对称点行为诡异压力放大器,制造不可预测性
Clyde近则撤退,远则追击胆小摸鱼制造节奏凹陷 + 控制左下死角

第三层:几乎无人察觉的模式切换

上面所有的目标格算法,只在追踪模式(Chase)下生效。幽灵还有另外两种模式。

散步模式(Scatter)

在散步模式下,每个幽灵的目标格被替换成迷宫四角中固定的一个:Blinky 右上、Pinky 左上、Inky 右下、Clyde 左下。由于目标点位于墙外的不可达位置,幽灵会在各自的角落里绕圈。

游戏在散步与追踪之间按固定时间表来回切换。以第一关为例,切换序列大致为:

散步 7 秒 → 追踪 20 秒 → 散步 7 秒 → 追踪 20 秒
→ 散步 5 秒 → 追踪 20 秒 → 散步 5 秒 → 此后永久追踪

随着关卡推进,散步时长逐步缩短、追踪时长延长,直到高关卡几乎不再有散步阶段。这就是《吃豆人》真正的难度曲线——不是幽灵变快,不是迷宫变复杂,而是喘息时间被系统性地压缩。

而绝大多数玩家从未意识到这个机制存在。他们只会说「后面的关卡感觉更凶了」。

设计提取:最好的难度曲线是玩家能感受到、但无法指出来源的。当难度提升表现为一个可见的数值(敌人血量 +50%),玩家会把注意力转向数值;当它表现为节奏结构的变化,玩家会把它体验为「我需要更专注」。后者产生投入,前者产生抱怨。

惊慌模式(Frightened)

玩家吃下能量豆后,幽灵进入惊慌模式:变蓝、减速、并且——这是关键——转向决策改为随机

这是全局唯一使用随机数的地方,而且它的位置选得极准:只在玩家占据优势的短暂窗口内引入随机性。这保证了「追猎幽灵」的阶段不会退化成一道确定性的最优解计算题,同时又不会让玩家在受压迫时遭遇不公平的随机死亡。

另外,模式切换发生的瞬间,所有幽灵会立即掉头一次——这是全局唯一被允许的 180° 转向。这个细节给了玩家一个清晰的视听提示:局势变了。

回到 1980 年:为什么是「吃」而不是「打」

技术层之外,还有一层同样重要的历史事实:岩谷彻的设计出发点,是把女性玩家带进街机厅

1980 年的街机厅以射击与竞速为主,受众几乎全是男性青少年。岩谷彻的判断是,这个品类的核心动词——「射击」——本身就在筛选受众。他选择的替代动词是「」与「」。

这个决策的连锁反应几乎重塑了整个行业:

  • 没有暴力表现,因此可以放进餐厅、商场、电影院大堂——街机的物理分布被改写
  • 角色造型必须可爱且可识别,催生了游戏史上第一个成规模的官方周边体系
  • 它成为首款在北美大规模授权的日本游戏,为此后的日本主机产业铺了渠道

值得强调的是:这是游戏史上第一次有明确记录的、以受众扩展为目标的设计实验。而它成功的方式不是「降低难度」或「简化操作」,而是更换核心动词。今天每一个讨论「如何扩大受众」的项目,都值得先问一遍这个问题:我们的核心动词在筛掉谁?

第 256 关:一个 8 位整数的边界

《吃豆人》的关卡计数器是一个 8 位无符号整数,取值范围 0–255。当玩家通过第 255 关进入下一关时,计数器溢出归零。

绘制关卡底部水果图标的例程会依据关卡数决定绘制多少个图标。当这个值溢出后,例程会尝试绘制 256 个图标,写入范围远超屏幕右半区的显存边界,导致画面右侧一半被垃圾数据填满——著名的「Kill Screen」。左半屏仍然可玩,但右半屏的豆子无法被正确渲染与吃掉,关卡因此无法完成。

社区对它的定性一直有分歧:

它是 Bug、是设计边界,还是某种「天然终点」?

「纯粹 Bug」立场:这是一个明确的整数溢出缺陷,没有任何证据表明设计者意图如此。1980 年的开发者根本不认为会有人打到第 256 关——这在当时是一个物理上难以想象的成就(1999 年 Billy Mitchell 首次完成公开认证的满分通关,用时约六小时)。

「功能性终点」立场:无论意图如何,它事实上为一款无尽循环的游戏提供了终点,从而使「完美通关」这个概念成为可能。没有 Kill Screen,《吃豆人》的最高分就没有上限,竞技文化也就无从建立。

本文的判断:两者不矛盾。这是一个缺陷,但它揭示了一件真实的事——任何无尽系统都需要一个边界才能被赋予意义。设计者没有提供这个边界,8 位整数替他提供了。后来的街机与竞速游戏开始有意设计终点与结算,某种程度上正是学到了这一课。

迁移到现代项目:一份可用的骨架

这套四十多年前的结构,今天依然是「性格化敌人」这一需求的最优起点。核心思想只有一句:把行为差异收敛到一个函数里

// 共用:所有敌人一套移动与状态机,零重复
abstract class GhostBrain {
  mode: "scatter" | "chase" | "frightened" = "scatter";

  // 唯一的差异点 —— 子类只需实现这一个方法
  abstract chaseTarget(player: Actor, world: World): Cell;

  // 散步锚点:每个敌人一个固定角落,用于制造节奏凹陷
  abstract scatterCorner(): Cell;

  currentTarget(player: Actor, world: World): Cell {
    switch (this.mode) {
      case "chase":      return this.chaseTarget(player, world);
      case "scatter":    return this.scatterCorner();
      case "frightened": return world.randomReachableCell();
    }
  }

  // 共用:路口贪心 + 禁止掉头 + 固定优先级裁决
  decideAt(junction: Cell, incoming: Dir, target: Cell, world: World): Dir {
    const order: Dir[] = ["up", "left", "down", "right"];   // 并列时的裁决顺序
    return order
      .filter(d => d !== opposite(incoming) && world.walkable(junction.step(d)))
      .reduce((best, d) =>
        sqDist(junction.step(d), target) < sqDist(junction.step(best), target) ? d : best);
  }
}

// 四个「性格」= 四个两行的子类
class Chaser  extends GhostBrain { chaseTarget(p) { return p.cell; } … }
class Flanker extends GhostBrain { chaseTarget(p) { return p.cell.step(p.facing, 4); } … }
class Amplifier extends GhostBrain {
  constructor(private anchorAlly: GhostBrain) { super(); }
  chaseTarget(p) {
    const pivot = p.cell.step(p.facing, 2);
    return pivot.plus(pivot.minus(this.anchorAlly.cell));   // 点对称翻转
  }
  …
}
class Skittish extends GhostBrain {
  chaseTarget(p) { return dist(this.cell, p.cell) > 8 ? p.cell : this.scatterCorner(); }
  …
}

在这个骨架之上,四个关键参数决定了整体手感:

  1. 散步/追踪的时间表——你的难度曲线真正藏在这里,而不在敌人属性里
  2. 贪心 vs 最优寻路——保留可被玩家学习和利用的失败模式
  3. 随机性的投放位置——只在玩家占优的窗口内使用,避免不公平死亡
  4. 是否存在一个「放大器」角色——依赖友方状态的敌人,能用极低复杂度制造不可预测性
一句话总结:性格不是四套 AI,是一套 AI 的四个参数。任何准备给敌人做「个性」的项目,都应该先确认这一点——否则你会写出四份互相无法组合、也无法调试的行为树。

本词条的下一步

本词条计划中的后续补充与关联条目:

  • 散步/追踪时间表的完整逐关数据表(含 Cruise Elroy 阈值)
  • Midway 北美版与 Namco 原版的参数差异对照
  • 《求生之路》AI Director 条目(同轴,2008)——从「敌人性格」到「系统编排节奏」的演进
  • Rogue 条目(独立里程碑轴,1980)——同一年,另一条用规则替代内容的路径

如果你对基板行为有实测数据、或对本文的算法描述有修正意见,欢迎在议事厅提出;经核验的修正会计入词条修订记录并署名。

词条标签
吃豆人AI算法幽灵寻路逻辑岩谷彻可控恐惧设计街机AI历史256关Bug行为状态机起源Blinky Pinky Inky Clyde
溯源 · 主要依据
  1. 《The Pac-Man Dossier》,Jamey Pittman — 对幽灵目标格与模式切换周期最完整的逆向工程记录
  2. 岩谷彻公开访谈合集(1980s–2010s) — 设计意图与受众扩展目标的一手陈述
  3. Namco 原始街机基板 ROM 反汇编社区注释 — 8 位计数器溢出与第 256 关行为的验证
星链 · 跨轴相关词条
独立里程碑
Rogue:把「死亡」写进叙事的第一次尝试
待点亮
玩法革命
1-1 的隐形教程:不说话的说明书
待点亮

议事厅ROUNDTABLE

8 个议题96 条回复57 位参与者最近活跃 2026/07/27

最容易被忽略的一点:四个幽灵的差异全部来自「目标格怎么算」这一个函数,其余逻辑完全共用。这才是真正的工程美感——性格不是四套 AI,是一套 AI 的四个参数。任何想给敌人做性格的项目都应该先抄这个结构。

状态机守夜人 · 2026/07/27 · 策展人置顶
← 返回主题轴:玩法革命