Games104学习笔记(20)
GAMES104:游戏引擎 Gameplay 玩法系统:高级 AI(上)
课程:GAMES104《现代游戏引擎:从入门到实践》
第 17 讲(上):游戏引擎 Gameplay 玩法系统:高级 AI
本地视频时长:约 1 小时 47 分钟
一、从反应式 AI 到规划式 AI
有限状态机和行为树擅长按照预先设计的结构响应环境,但复杂任务常包含多种完成方式,且执行条件会随玩家行为变化。此时,把所有可能分支预先写进状态或树结构,会使逻辑快速膨胀。
规划式 AI 的思路是:设计者提供目标、动作、约束和世界状态,规划器在运行时或离线阶段组合出行动序列。它不再只回答“当前执行哪一个节点”,而是回答“为了实现目标,接下来应该依次做什么”。
本讲主要介绍三类方法:
| 方法 | 核心思想 | 典型用途 |
|---|---|---|
| HTN | 将高层任务逐步分解为可执行的基础任务 | 结构明确、带领域经验的长程行为 |
| GOAP | 在状态与动作构成的图上搜索低成本计划 | 目标明确、动作组合需要动态变化的 AI |
| MCTS | 用大量模拟逐步扩展高价值决策分支 | 状态空间巨大、适合前瞻博弈的决策 |
二、学习目标
- 理解世界状态、目标、动作、计划和执行器之间的关系。
- 掌握 HTN 的任务层级、方法选择、规划与重规划流程。
- 掌握 GOAP 的目标集、动作前置条件、效果和代价模型。
- 理解 MCTS 的选择、扩展、模拟、回传以及探索—利用平衡。
- 比较三类规划方法的优势、成本与适用边界。
三、规划系统的通用结构
规划方法虽然不同,但通常都依赖以下元素:
| 元素 | 作用 |
|---|---|
| Sensors | 从游戏世界提取 AI 可知的信息 |
| World State | 表示 AI 当前认知到的世界状态 |
| Goals 或 Root Task | 定义 AI 想实现的结果 |
| Actions 或 Tasks | 表示可以执行的行为及其条件 |
| Planner | 搜索或分解得到行动序列 |
| Plan Runner | 执行计划并跟踪结果 |
世界状态是 AI 的主观模型,不必等同于游戏的完整真实状态。它可能包含“看到敌人”“拥有药水”“生命值较低”“出口已知”等有限属性。感知系统更新这些属性,规划器只在这个抽象空间中推理。
规划系统的质量高度依赖抽象:状态过少,计划无法区分关键情形;状态过细,搜索空间和维护成本会急剧上升。
四、HTN:按层级分解任务
1. 基本思想
HTN,即 Hierarchical Task Network,把复杂目标表示为层级任务。高层任务不能直接执行,需要通过某种方法分解为更小的子任务,直到得到一串可执行的基础任务。
例如“生存”可以分解为:
- 有药水时:使用药水。
- 有材料时:制作药水,再使用药水。
- 有金币时:购买药水,再使用药水。
- 条件都不满足时:逃跑或寻找资源。
设计者不是直接写死唯一行动序列,而是为同一个任务提供多种分解方法,并为每种方法定义适用条件。
2. HTN 的组成
HTN 框架通常由四部分构成:
| 组成 | 内容 |
|---|---|
| World State | AI 已知的属性和状态 |
| HTN Domain | 任务层级、分解方法与前置条件 |
| Planner | 根据当前状态选择方法并生成计划 |
| Plan Runner | 按顺序执行基础任务并更新状态 |
感知系统负责把游戏世界转化为 World State;Domain 保存设计者的领域知识;Planner 负责组合任务;Runner 则把计划落到实际 Gameplay 系统。
3. 基础任务
基础任务是可以直接执行的行为,例如移动到指定位置、使用物品、攻击敌人或播放交互。
一个基础任务通常包含:
- 前置条件:当前是否允许执行。
- 操作:真正调用的行为。
- 效果:成功后世界状态如何改变。
- 成败结果:供计划执行器决定是否继续。
基础任务应尽量稳定、粒度清晰。若一个基础任务内部又隐藏大量决策,它实际上仍是一个复合任务,会削弱规划器的可见性。
4. 复合任务与方法
复合任务不能直接执行,而是包含多个候选方法。每个方法由前置条件和一串子任务组成,并可具有优先级。
规划时,系统按规则寻找第一个满足条件的方法,把它展开为子任务;若子任务仍是复合任务,则继续递归分解。最终输出一串基础任务。
这种结构把设计者经验编码为“当环境满足某条件时,可用哪种解决方案”。它能生成长程、可解释的计划,也比纯状态机更容易复用高层行为。
5. HTN 规划过程
规划器通常在临时状态副本上进行分解:
- 从根任务开始。
- 检查复合任务的候选方法。
- 选择前置条件满足的方法。
- 递归展开子任务。
- 遇到基础任务时,验证其前置条件。
- 假设任务成功,并把效果写入临时世界状态。
- 所有任务成功展开后,得到最终计划。
临时状态的作用是让后续任务看到前面任务的预期效果。例如“制作药水”会在临时状态中增加药水数量,使后续“使用药水”的前置条件能够成立。
若某个基础任务条件不满足,规划器需要回退并尝试其他方法。若所有候选方法都失败,则整个规划失败。
6. 执行与重规划
计划生成后由 Runner 顺序执行。现实游戏环境并不会严格按照规划预测发展:玩家可能抢走资源,目标可能死亡,出口可能被封锁。因此系统需要在以下情况重新规划:
- 当前没有计划。
- 当前计划已完成。
- 某个任务执行失败。
- 感知到的世界状态发生关键变化。
重规划频率过低会让 AI 固执执行失效计划,过高则会浪费计算,并导致角色频繁改变意图。工程中通常根据关键状态变化触发,并辅以冷却和优先级。
7. HTN 的优势与局限
优势:
- 层级结构适合表达长程任务。
- 计划结果清晰,便于调试和解释。
- 领域知识可直接编码到任务分解中。
- 规划成本通常比在完全自由的动作空间中搜索更低。
局限:
- Domain 需要设计者预先组织大量任务与方法。
- 玩家行为不可预测时,计划容易失效。
- 世界状态和任务效果的抽象很难一次设计正确。
- 过强的层级约束可能限制 AI 产生新组合。
五、GOAP:围绕目标搜索动作序列
1. 基本思想
GOAP,即 Goal-Oriented Action Planning,不要求设计者直接给出任务分解树,而是定义目标和一组动作。规划器根据当前状态,搜索一串能把世界变成目标状态的动作。
整体流程是:
- 从 Goal Set 中选择当前最重要且尚未满足的目标。
- 在 Action Set 中搜索能够实现该目标的动作序列。
- 执行计划。
- 当环境变化或计划失败时重新选择目标并规划。
2. 目标集
一个目标通常包含:
- 目标前置条件:何时该目标可以被考虑。
- 目标状态:完成后希望哪些世界状态成立。
- 优先级:多个目标同时可用时如何选择。
例如“恢复生命”“消除威胁”“保护队友”“巡逻”等目标可以同时存在,但 AI 会根据当前生命值、敌人状态和任务要求选择优先目标。
目标优先级可以是固定值,也可以根据世界状态动态变化。动态优先级更灵活,但必须防止两个目标在相近分值间来回切换。
3. 动作集
一个 GOAP 动作可以表示为:
$$ a = \left(P_a, E_a, C_a\right) $$
其中 $P_a$ 是前置条件,$E_a$ 是执行后的效果,$C_a$ 是动作代价。
例如“购买药水”的前置条件是拥有足够金币并能到达商店;效果是药水数量增加、金币减少;代价可以包含时间、距离、风险或资源消耗。
4. 将规划转成图搜索
世界状态的不同组合可视为图节点,动作是连接状态的边,动作代价是边权重。规划问题因而可以转化为从当前状态到目标状态的低成本路径搜索。
若当前状态为 $s_0$,目标条件为 $G$,行动序列为 $\pi=(a_1,a_2,\ldots,a_k)$,规划器希望找到满足目标且总代价较低的序列:
$$ \pi^* = \arg\min_{\pi}\sum_{i=1}^{k} C_{a_i} $$
搜索可以从当前状态正向应用动作,也可以从目标状态反向寻找能产生所需效果的动作。后者常能减少与目标无关的候选动作。
5. GOAP 的优势与局限
优势:
- 目标与具体行为解耦,同一目标可以产生不同计划。
- 新增动作后,现有目标可能自动获得新的实现方式。
- 比 HTN 更容易产生设计者没有显式列出的动作组合。
- 代价函数可让 AI 在时间、风险和资源之间权衡。
局限:
- 运行时搜索通常比 HTN 分解更慢。
- 状态、动作前置条件和效果难以完整、准确地建模。
- 动作数量与状态维度增大后,搜索空间迅速膨胀。
- 抽象模型与真实执行不一致时,计划会频繁失败。
六、HTN 与 GOAP 的对比
| 维度 | HTN | GOAP |
|---|---|---|
| 主要输入 | 层级任务与分解方法 | 目标、动作、前置条件、效果与代价 |
| 计划来源 | 递归分解高层任务 | 在状态—动作空间中搜索 |
| 设计者控制 | 强,计划结构较可预测 | 较弱,动作组合更动态 |
| 运行时成本 | 通常较低 | 通常较高 |
| 可解释性 | 高,任务层级清晰 | 较高,可查看目标和动作序列 |
| 主要风险 | Domain 编写繁重、限制新组合 | 状态空间膨胀、模型容易不一致 |
HTN 更像把专家经验组织成层级配方;GOAP 更像给出目标和工具,让规划器自行寻找一条可行路径。实际项目可以组合两者:高层用 HTN 约束战略结构,局部任务内部再用 GOAP 搜索行动。
七、MCTS:在巨大决策空间中做前瞻搜索
1. 为什么需要采样式搜索
围棋等问题的完整状态空间极其庞大,无法穷举所有行动序列。蒙特卡洛树搜索通过反复模拟,把计算集中到更有希望的分支,在有限预算内逐步改善决策质量。
在搜索树中:
- 节点表示游戏状态。
- 边表示一次动作。
- 从根到节点的路径表示一串行动。
MCTS 不要求一次构造完整搜索树,而是边采样、边统计、边扩展。
2. 四个基本阶段
每轮 MCTS 通常包含四个阶段:
- Selection:从根节点沿选择策略向下,找到可扩展节点。
- Expansion:选择一个未尝试动作,创建新的子节点。
- Simulation:从新节点出发,按照默认策略快速模拟到终局或截断条件。
- Backpropagation:将模拟结果沿访问路径反向更新到各祖先节点。
重复足够多轮后,访问次数和平均收益会逐渐反映各分支的潜力。
3. 默认策略
模拟阶段需要一个能够快速行动的默认策略。最简单的是随机行动,但完全随机可能产生大量低质量样本。也可以使用简单规则、启发式或轻量模型,使模拟结果更接近合理玩法。
默认策略不必达到最终 AI 的水平,它的重点是成本低、覆盖广,并能提供有区分度的结果。
4. 回传
模拟完成后,结果沿当前路径回传。每个经过的节点更新访问次数与累计收益,例如:
- 胜利记为 $1$。
- 失败记为 $0$ 或 $-1$。
- 平局记为中间值。
不同玩家轮流行动时,还需要从当前节点所属玩家的视角处理收益符号,否则搜索会错误地假设双方都在帮助同一个玩家。
5. 探索与利用
选择阶段面临两个目标:
- 利用:继续搜索当前平均收益较高的分支。
- 探索:尝试访问次数少、结果仍不确定的分支。
只利用会过早锁定看似优秀的动作,只探索则无法把预算集中到高价值区域。常用的上置信界形式为:
$$ \mathrm{UCB}_i = \bar{X}_i + C\sqrt{\frac{\ln N}{n_i}} $$
其中 $\bar{X}_i$ 是子节点 $i$ 的平均收益,$n_i$ 是该子节点访问次数,$N$ 是父节点访问次数,$C$ 控制探索强度。
第一项鼓励选择已知收益高的分支,第二项鼓励尝试访问较少的分支。随着 $n_i$ 增加,不确定性奖励逐渐减弱。
6. 计算预算与最终动作
MCTS 通常按以下预算之一终止:
- 固定模拟次数。
- 固定计算时间。
- 固定内存或树节点数量。
终止后,可选择访问次数最多的根节点子分支,也可以选择平均收益最高的分支。访问次数通常更稳定;平均收益可能受少量幸运模拟影响。
实时游戏必须严格控制预算。MCTS 的优势是可以随时停止并给出当前最好答案,但动作模型、模拟速度和状态复制成本仍可能成为瓶颈。
7. MCTS 的优势与局限
优势:
- 不需要完整展开巨大状态空间。
- 搜索具有 anytime 特性,预算越多通常结果越好。
- 各分支模拟相对独立,具备并行化潜力。
- 行为具有一定多样性,不容易完全固定。
局限:
- 状态与动作必须能够快速复制和模拟。
- 实时连续世界难以直接建立精确模型。
- 搜索质量依赖默认策略、奖励和预算。
- 大量模拟仍可能无法覆盖关键但稀有的行动。
八、如何选择规划方法
| 场景特征 | 更适合的方法 |
|---|---|
| 行为流程较明确,需要设计者严格控制 | HTN |
| 目标明确,希望动作按环境动态组合 | GOAP |
| 状态空间巨大,可快速模拟未来结果 | MCTS |
| 强调即时反应、逻辑规模有限 | 行为树或状态机 |
选择时不能只看算法能力,还要评估状态表示成本、调试工具、设计师工作流、运行时预算和行为可预测性。越强大的自动规划,通常越需要更好的可视化和解释工具。
九、设计与工程原则
- 先定义 AI 能知道什么,再定义它能规划什么。
- 状态、前置条件与效果必须和实际 Gameplay 行为保持一致。
- 规划失败、执行失败和世界变化都应有明确的重规划策略。
- 用层级或启发式缩小搜索空间,不要把整个游戏世界直接交给规划器。
- 为计划、候选方法、动作代价和搜索统计提供可视化调试能力。
十、要点回顾
- 规划式 AI 通过世界状态、目标和动作动态生成行动序列。
- HTN 用领域知识把高层任务递归分解为可执行的基础任务。
- GOAP 把规划转为状态—动作图搜索,以动作代价比较不同计划。
- MCTS 通过选择、扩展、模拟与回传,在有限预算内探索巨大决策空间。
- UCB 同时考虑平均收益与访问不确定性,实现探索和利用之间的平衡。