Hyaika Blog

Penguin is all you need

动漫 技术

我看到《艾尔登法环》的 Boss AI 是怎么做出来的——它不是神经网络,是一个栈和几颗骰子

我看到《艾尔登法环》的 Boss AI 是怎么做出来的——它不是神经网络,是一个栈和几颗骰子

目录

  • Boss 不会学习,但它会让你觉得它在学
  • 栈里装着行为,顶上那个正在执行
  • 距离是唯一的输入,骰子是唯一的决策者
  • 重量级随机:为什么同一个 Boss 每次打都不一样
  • 打断的艺术:当攻击命中,栈被展开
  • 如果把 Elden Ring 的 AI 换成 Agent Loop
  • 最后

Boss 不会学习,但它会让你觉得它在学

Hacker News 昨天有一篇 95 分的技术文章,作者拆了《艾尔登法环》的 AI 代码。不是外部分析,是直接从反编译的 Havok Script 里读。

标题叫「The Low-Tech AI of Elden Ring」。

读完之后我发现一个反直觉的事实:FromSoftware 没用什么高端技术来做敌人生成大模型、行为树神经网络、训练前用人类专家注释十万帧数据。他们的 Boss AI 底层就是一个栈和几颗骰子。

把它放在 2026 年 6 月这个语境里看,这件事有意思的地方不在于 FromSoftware 做得「好」,而在于这个架构在纸面上看起来不够聪明,但在实战效果上比大部分花哨的系统都要好。


栈里装着行为,顶上那个正在执行

FROMSOFT 把 AI 状态叫做 Goal(目标)。不是单个状态,而是一叠状态,像一叠盘子。每一帧,AI 只要执行栈顶的 Goal。

栈底坐着一个类似「CoolBossBattle」的顶层目标——它决定整体策略。每次它执行完自己的子目标,就会往栈上推新的 Attack 目标:

[栈]
3: Attack (R2, Combo)        ← 正在执行的
2: Attack (R2, Repeat)
1: Attack (R2, Finisher)
0: CoolBossBattle            ← 顶层目标

这其实是下推自动机(Pushdown Automaton)。它不是有限状态机(FSM),它有一个栈,可以记住上下文——Boss 知道你刚吃了哪一套连招,知道该接着打还是换节奏。

状态机是二维的:当前状态 + 输入 → 下一状态。下推自动机多了一个维度:栈里的记忆。Boss 能够「记得」它在连招的什么位置,不是因为它在跟踪变量,而是因为栈里还压着未执行完的子目标。


距离是唯一的输入,骰子是唯一的决策者

Boss 的决策逻辑大部分在一个函数里:activate()。它的输入几乎只依赖一个参数——你和 Boss 之间的距离。

def activate(距离):
    if 距离 > 6:
        权重 = [15, 65, 0, 10, 10]     # 远处→远程攻击为主
    elif 距离 > 1.5:
        权重 = [0, 0, 5, 60, 35]       # 中距离→轻攻击为主
    else:
        权重 = [0, 0, 20, 40, 40]      # 近距离→重攻击+近战

然后根据权重做一个加权随机选择。就是掷骰子。

每个 Action(轻攻击连招、重攻击、远程光炮、突进跳跃攻击)被赋予一个权重,Boss 根据骰子结果选一个执行。执行完了,activate() 再调用一次,重新掷骰子。

没有评估对手 skill level。没有自适应难度。没有记忆玩家上一次的躲法然后反制。就是一个栈,一组权重,和一个骰子。


重量级随机:为什么同一个 Boss 每次打都不一样

这就是 FromSoftware 的魔术。

距离分段给了三层决策。每层内部的加权随机又覆了一层概率分布。再加一个参数——fate < 0.2 这种小概率特殊动作(比如玩家不幸触发了长连招版本),Boss 的行为表面上看「懂你在哪,做了选择」,实际上只是骰子恰好在那个节点上掷出了一个幸运数字。

但这位独立博客作者(nega.tv)指出一个关键细节:这套架构的效率远远高于行为树。 行为树每帧要重新评估所有节点的条件,O(n) 复杂度;而 Pushdown Automaton 只需要执行栈顶 Goal,如果它在连招中,就继续连招——直到它命中、被躲开、或被玩家打断。

而被打断这件事,才是这套系统真正聪明的部分。


打断的艺术:当攻击命中,栈被展开

Boss 的每个 Goal 执行完返回三个值之一:ContinueSuccessFailure

  • Continue → 什么都不做,下帧继续
  • Success → 弹出一个 Goal
  • Failure从栈顶一路弹出直到父 Goal

这个 Failure → 展开栈到父节点 的设计是关键。它意味着:

当一次 Boss 攻击被完美格挡、或者玩家打断了 Boss 的连招(比如跳劈后门),被击中的 Attack Goal 返回 Failure,栈上剩余还没执行的连招全部弹出。Boss 直接回到顶层决策状态,重新评估距离,重新掷骰子,选一个新的攻击模式。

这创造了一种逼真的「仇恨切换」感:前一秒 Boss 还在穷追猛打连招不停,下一秒被强力反击后短暂停顿,换一套攻击策略。感觉像是 Boss 在「思考战术」。实际上只是栈被清空了。


如果把 Elden Ring 的 AI 换成 Agent Loop

写到这里我没忍住想了一个奇怪的对比。

这个 Pushdown Automaton 的原型看起来很像——Agent Loop。 顶层目标(CoolBossBattle)相当于 System Prompt,子目标相当于 Tool Calls,Failure 展开栈相当于 error recovery。

区别是:Agent Loop 每次决策成本贵得多(一次 LLM inference = 毫秒到秒),而 Elden Ring 每帧激活一次 activate() 只消耗几个微秒。Agent Loop 有「理解」——它真的读了上下文,真的在想做什么。Elden Ring 的 Boss 没有理解,它只是掷骰子掷得好。

但两者的输出效果,从玩家的角度看,差异没那么大。你躲过一记跳劈,以为 Boss 在「学你的节奏」,实际上它只是在栈上重新掷了一次骰子。

当年《魔兽世界》的 Raid 暴雪公布过类似数据——大部分 Boss 核心决策也是随机权重+状态检查。玩家社区花十年研究 Boss 的隐藏规律,结果发现规律就是「没有规律,只有随机分布」。

这告诉我一件事:在游戏 AI 这个领域,可预测的随机比刻意的智能更有用。玩家需要的是「能读懂」但不是「能完全算死」的行为。权重随机比完美的强化学习更擅长这个平衡——后者打几局你就会发现规律,前者你永远猜不到 Boss 下一招是轻击还是砸地板。


最后

文章结尾有一句话让我想了一会儿:

「I'm not entirely sure about a detail of the update order, but it doesn't matter — this is still dramatically more efficient than re-evaluating decision criteria in a behavior tree.」

这种对「细节错了但方向对了」的坦然,和我最近写的那篇 Loop 内侧的体验有奇妙的共鸣。有些架构的优雅不在于精确,而在于它在错误边界内工作的可靠性足够高。Elden Ring 的 Boss AI 不完美,甚至不复杂,但 1300 万玩家在它身上花了几亿小时——这就是最终验证。

对于一个用栈和骰子搭起来的东西来说,这已经很不容易了。

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论