设想一座废弃的疗养院:一层大厅有三条通往地下车库的路线,东侧楼梯最短,中间的电梯井最隐蔽,西侧的洗衣房通道最绕。玩家前三次都选了东侧楼梯,第四次怪物就等在那里。有的玩家会觉得毛骨悚然,觉得这个怪物“记住了我”;也有的玩家会摔手柄,觉得“它明明看不见我”。同样的行为,被前者视为智能,被后者视为作弊,分界线在于怪物做出这个判断的依据,是不是玩家有机会察觉、也有机会影响的东西。

热度图:把路线变成网格上的数字

怪物要学习路线,首先要有一个可以累积经验的表示。最直接的做法是在导航网格(NavMesh)上做统计:把每个可行走多边形(或者更细的规则网格)当成一个计数器,玩家每次经过,就在对应位置加一点热度,再沿路径方向做少量扩散,得到一张“玩家常走在哪里”的热度图。

直接用这张图有两个问题。其一,路线的重要性并不只由走过的次数决定:玩家逃跑时一定要经过的门口和狭窄处,热度必然高,但那是地形逼出来的,并非玩家偏好。所以热度需要除以“这个位置在所有可选路线中的必经程度”,比如用瓶颈度或该格子的通过率做归一。其二,只统计逃跑时的路径才有意义,探索时的乱走会把热度图弄脏,需要用“身后有追击者”这一状态来给样本打标。

导航网格平面图上叠着发光的逃跑路线与热度光晕,怪物脚印沿最热路线走到岔口后分成两支去搜索。
怪物AI统计玩家常用的逃跑路线,形成热度图,并在关键岔口分头搜索,而不是全图乱找。

从热度到先验:怪物没有作弊,它在猜

这一步是整套设计里最关键的一步。怪物不应该拿到玩家当前的坐标,它拿到的是:玩家上一次被感知的位置、发出声响的方位、留下的痕迹(打开的门、熄灭的灯、脚印),以及那张热度图。搜索时,这些信息合成一个概率分布,怪物按概率高低安排巡查顺序。

// 搜索先验草图(示例)
for cell in navmesh.cells_within(radius = search_radius):
    p_route   = heat[cell] * decay(now - last_hit[cell])   // 历史路线
    p_sense   = evidence_kernel(cell, sounds, traces)       // 当前可感知证据
    p_reach   = reachable(last_seen_pos, cell, t_elapsed)   // 物理上来不来得及
    prior[cell] = p_reach * (w_route*p_route + w_sense*p_sense) + noise

target = sample(prior, temperature = T)   // 按概率采样,不取最大值

注意最后一行:按概率采样,而不是永远选最大值。如果怪物永远去热度最高的格子,玩家只要观察到它总是先去楼梯口,就能反过来布局;采样让同一个先验产生不同的行为,也让玩家能感到怪物“在犹豫”。可达性项也很重要,它保证怪物不会在玩家刚从东侧消失两秒之后,就出现在西侧的洗衣房尽头。

遗忘与随机:先验必须会过期

热度不衰减,怪物就会被玩家最早期的习惯永久绑住。更糟糕的是,玩家一旦为了躲开它而改用新路线,怪物仍守在旧路线上,就成了一个只会守株待兔的固定哨兵。因此需要两种遗忘:随时间的指数衰减,让三十分钟前的走法权重明显低于刚才的;以及“命中即更新”,当怪物赶到预测位置却扑空,那个格子的热度要被立刻削弱,等于怪物承认自己猜错了。

随机性也不是可有可无的调味。在先验上叠加少量均匀噪声,怪物就偶尔会去检查一条几乎没人走的路,玩家因此永远不能确定“换到冷门路线就百分之百安全”。这种不确定性太少会显得死板,太多又让学习失去意义,需要与下面的旋钮一起调。

记录路径热度热度衰减叠加声音痕迹生成搜索先验概率巡查
怪物的“学习”只发生在热度图和先验分布上,它要靠感知去验证,而不是直接知道玩家在哪里。

三个旋钮和一份取舍表

旋钮调高的效果 调低的效果 示例参数
学习速度 两三次就被针对,压迫感强怪物长期显得“没脑子” 单次逃跑热度增量0.15
遗忘速度 玩家换路线很快脱身 旧习惯长期被针对热度半衰期约8分钟
搜索半径 覆盖面广,逃跑难度大怪物只守点,容易预测以最后感知点为圆心,30—45米
采样温度行为分散,更难读 行为集中,更像“记住了” T取0.6—1.2

这些数值都是示例,真正的设定要在具体地图上测。一个实用的判据是“反制时间”:玩家发现自己被针对以后,需要几分钟、几次尝试才能通过换路线摆脱。如果这个时间超过两三次尝试,玩家会觉得系统在追杀自己而不是在与自己博弈。

与关卡设计的约束:安全走廊不能被学掉

关卡设计师往往会在地图里留下“容错区”:一两条经过设计的、风险较低的路线,用来给新手兜底,也给紧张的玩家喘息。路线学习如果不加约束,最先被学到的恰恰就是这些走廊,因为玩家最常走它们。所以需要在数据层给这些区域标记“先验上限”,规定怪物在这里的搜索权重不能超过某个值,或者只能在特定叙事事件里才可以突破。关于如何在整个导演层面给恐怖事件设定授权范围,可以参考导演系统与事件库的思路,路线学习只是其中一个只负责“往哪里去”的执行部件。

从实现走向体验

PA真人游戏世界智能研究组把这类路线学习放在“感知—先验—执行”三层里,热度图和先验属于中间层,执行层仍然使用传统的行为树与寻路。这样做的好处是每一层都可以单独调试:设计师看到的是一张可视化的热力图,而不是一个说不清来龙去脉的黑箱。测试时不妨让人在热力图旁边看着怪物行动,问一句“它为什么去那里”,能用热度、声音或痕迹解释清楚,才算通过。

PA真人的演示方案也把“玩家换路线即可摆脱”当作验收条件之一。再往后的问题还有不少:多只怪物之间怎样共享或不共享热度,玩家在联机时路线被平均后会发生什么,以及学习得来的先验要不要跨局保留。这些目前都没有好答案。如果你更关心怪物每一次出场之后玩家的感受会怎样变化,可以继续读恐怖刺激的疲劳问题,更多同类讨论在PA真人AI恐怖游戏栏目