# 游戏 AI 系统设计
> 好的游戏 AI 不是最聪明的,而是**最有趣的**。玩家的乐趣来自可理解、可预测但又充满惊喜的对手行为。
---
## 目录
1. [AI 设计哲学](#ai-设计哲学)
2. [寻路系统](#寻路系统)
3. [行为树(Behavior Trees)](#行为树behavior-trees)
4. [目标导向行动规划(GOAP)](#目标导向行动规划goap)
5. [效用系统(Utility AI)](#效用系统utility-ai)
6. [群体 AI 与涌现行为](#群体-ai-与涌现行为)
7. [感知与信息模型](#感知与信息模型)
8. [机器学习在游戏 AI 中的应用](#机器学习在游戏-ai-中的应用)
9. [三大引擎 AI 工具对比](#三大引擎-ai-工具对比)
10. [经典案例分析](#经典案例分析)
---
## AI 设计哲学
### 游戏 AI 与学术 AI 的区别
| 维度 | 学术 AI | 游戏 AI |
|------|---------|---------|
| **目标** | 最优解 | 有趣的行为 |
| **可解释性** | 不重要 | 必须可理解 |
| **性能要求** | 可离线计算 | 16ms 内完成 |
| **资源限制** | 无限制 | CPU 预算 5-20% |
| **容错性** | 零错误 | 偶尔犯错更真实 |
| **可预测性** | 避免 | 适度可预测 |
### AI 难度设计
```
难度调节维度:
├── 反应速度(Reaction Time)
│ └── 简单: 500ms → 困难: 50ms
├── 准确度(Accuracy)
│ └── 简单: 30% → 困难: 95%
├── 信息优势(Information)
│ └── 简单: 仅视觉 → 困难: 全图知晓
├── 资源效率(Efficiency)
│ └── 简单: 浪费弹药 → 困难: 最优经济
├── 协作能力(Coordination)
│ └── 简单: 单独行动 → 困难: 团队配合
└── 错误率(Error Rate)
└── 简单: 频繁犯错 → 困难: 极少失误
```
### AI 可玩性原则
| 原则 | 说明 | 反例 |
|------|------|------|
| **可读性** | 玩家能理解 AI 在做什么 | 瞬移、无动画状态切换 |
| **公平感** | AI 似乎遵守同样规则 | 无限弹药、穿墙 |
| **个性** | 不同 AI 有不同行为风格 | 所有敌人行为一致 |
| **适应性** | AI 对玩家行为有反应 | 无视玩家策略 |
| **失误** | 偶尔犯人类会犯的错误 | 完美到不真实 |
---
## 寻路系统
### 算法对比
| 算法 | 时间复杂度 | 空间复杂度 | 最优性 | 适用场景 |
|------|-----------|-----------|--------|----------|
| **A\*** | O(E) | O(V) | ✅ | 标准网格寻路 |
| **Dijkstra** | O(E + V log V) | O(V) | ✅ | 无启发式统一代价 |
| **JPS** | O(E) 实际更快 | O(V) | ✅ | 均匀网格优化 |
| **Theta\*** | O(E) | O(V) | 近似 | 任意角度平滑路径 |
| **RRT** | O(n log n) | O(n) | 近似 | 高维空间、动态避障 |
| **NavMesh** | 预计算 | 预计算 | ✅ | 3D 复杂地形 |
### A* 算法详解
```python
# A* 伪代码
def astar(start, goal, heuristic):
open_set = PriorityQueue()
open_set.put(start, 0)
came_from = {}
g_score = {start: 0}
f_score = {start: heuristic(start, goal)}
while not open_set.empty():
current = open_set.get()
if current == goal:
return reconstruct_path(came_from, current)
for neighbor in neighbors(current):
tentative_g = g_score[current] + cost(current, neighbor)
if tentative_g < g_score.get(neighbor, INF):
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score[neighbor] = tentative_g + heuristic(neighbor, goal)
open_set.put(neighbor, f_score[neighbor])
return None # 无路径
# 常见启发式函数
def manhattan(a, b): # 4方向网格
return abs(a.x - b.x) + abs(a.y - b.y)
def euclidean(a, b): # 任意方向
return sqrt((a.x - b.x)**2 + (a.y - b.y)**2)
def octile(a, b): # 8方向网格
dx, dy = abs(a.x - b.x), abs(a.y - b.y)
return max(dx, dy) + (sqrt(2) - 1) * min(dx, dy)
```
### 高级寻路技术
#### 1. 分层寻路(Hierarchical Pathfinding)
```
《星际争霸2》寻路层级:
Level 1: 战区级别(Region Graph)
├── 将地图划分为连通区域
├── 区域间预计算连通性
└── 长距离路径:区域图 A*
Level 2: 集群级别(Cluster Graph)
├── 区域内部分为网格簇
├── 簇边界预计算最优路径
└── 中距离路径:簇图 A*
Level 3: 网格级别(Tile Grid)
├── 实际可行走网格
└── 短距离/最后阶段:网格 A*
效果:1000x1000 网格寻路从 50ms → <1ms
```
#### 2. 动态避障(RVO / ORCA)
```
RVO2 (Reciprocal Velocity Obstacles):
核心思想:
- 每个 agent 选择速度,避免与其他 agent 碰撞
- reciprocal:假设对方也会避让
- 局部最优:只考虑近期可能碰撞的目标
算法:
1. 计算与其他 agent 的速度约束半平面
2. 求解线性规划:在满足所有约束下最接近首选速度
3. 应用新速度
适用:群体移动、人群模拟、RTS 单位移动
```
#### 3. NavMesh 生成与使用
```
NavMesh 生成流程:
1. 体素化可行走表面(Voxelization)
2. 识别可行走区域(Walkable Clusters)
3. 构建轮廓(Contour Generation)
4. 简化为凸多边形(Convex Polygons)
5. 构建邻接图(Adjacency Graph)
运行时:
- A* 在 NavMesh 图上寻路
- 字符串拉动(String Pulling)优化路径
- 支持动态障碍物(NavMesh Obstacle)
```
---
## 行为树(Behavior Trees)
### 基础节点类型
```
行为树节点分类:
复合节点(Composite)
├── 序列(Sequence)→ 顺序执行,一个失败则全部失败
├── 选择器(Selector)→ 顺序执行,一个成功则全部成功
├── 并行(Parallel)→ 同时执行所有子节点
└── 随机选择器(Random Selector)→ 随机顺序尝试
装饰器(Decorator)
├── 反相(Inverter)→ 反转子节点结果
├── 重复(Repeater)→ 重复执行 N 次或无限
├── 直到失败(Until Fail)→ 重复直到失败
├── 冷却(Cooldown)→ 限制执行频率
└── 条件检查(Condition)→ 仅当条件满足才执行
叶节点(Leaf)
├── 动作(Action)→ 执行游戏行为
└── 条件(Condition)→ 检查世界状态
```
### 行为树示例:守卫 NPC
```
[Root] Selector
├── [Sequence] 战斗
│ ├── [Condition] 看到敌人?
│ ├── [Selector] 选择攻击方式
│ │ ├── [Sequence] 远程攻击
│ │ │ ├── [Condition] 距离 > 5m?
│ │ │ └── [Action] 射击
│ │ └── [Sequence] 近战
│ │ ├── [Condition] 距离 ≤ 5m?
│ │ └── [Action] 挥砍
│ └── [Action] 追击敌人
├── [Sequence] 巡逻
│ ├── [Condition] 到达巡逻点?
│ ├── [Action] 选择下一个巡逻点
│ └── [Action] 移动到巡逻点
└── [Action] 待机(Idle)
```
### 行为树与状态机对比
| 特性 | 状态机(FSM) | 行为树(BT) | 推荐场景 |
|------|-------------|------------|----------|
| **复杂度** | 简单直观 | 需要学习 | 简单 AI → FSM,复杂 AI → BT |
| **模块化** | 状态间紧耦合 | 节点可复用 | 模块化要求高 → BT |
| **扩展性** | 状态爆炸问题 | 层级组织优雅 | 大量行为 → BT |
| **调试** | 直观(当前状态) | 需追踪 tick 路径 | 调试频繁 → FSM |
| **性能** | O(1) 状态切换 | O(n) 节点评估 | 性能敏感 → FSM |
---
## 目标导向行动规划(GOAP)
### GOAP 核心概念
```
GOAP = 状态 + 动作 + 目标
世界状态(World State):
├── hasWeapon: true/false
├── nearEnemy: true/false
├── hasAmmo: true/false
├── health: 0-100
└── ...
动作(Action):
├── 前置条件(Preconditions)
│ └── 执行前必须满足的状态
├── 效果(Effects)
│ └── 执行后改变的状态
└── 代价(Cost)
└── 时间/资源/风险
目标(Goal):
├── 期望达到的世界状态
├── 优先级(Priority)
└── 可中断性(CanInterrupt)
```
### GOAP 规划示例
```
当前状态:无武器、无弹药、看到敌人
目标:杀死敌人
可用动作:
1. 拾取武器:前提: 武器在附近 → 效果: hasWeapon=true, cost=2
2. 拾取弹药:前提: 弹药在附近, hasWeapon=true → 效果: hasAmmo=true, cost=1
3. 装填:前提: hasWeapon=true, hasAmmo=true → 效果: weaponLoaded=true, cost=1
4. 射击:前提: weaponLoaded=true, nearEnemy=true → 效果: enemyDead=true, cost=1
5. 接近:前提: — → 效果: nearEnemy=true, cost=3
规划器求解:
当前 → 拾取武器 (2) → 拾取弹药 (1) → 装填 (1) → 接近 (3) → 射击 (1)
总代价:8
替代方案:
当前 → 接近 (3) → 近战攻击 (2) → enemyDead
总代价:5 ← 选择此方案(更低代价)
```
### GOAP vs 行为树
| 维度 | GOAP | 行为树 |
|------|------|--------|
| **决策方式** | 自动规划 | 手工编排 |
| **灵活性** | 高(自动组合动作) | 中(预定义结构) |
| **可预测性** | 较低 | 较高 |
| **性能** | 规划计算成本高 | 评估成本低 |
| **调试** | 难(需理解规划结果) | 易(可视化树结构) |
| **典型游戏** | F.E.A.R.、巫师3 | 光环、孤岛危机 |
---
## 效用系统(Utility AI)
### 核心思想
```
不同于行为树的"是否做",Utility AI 问"做哪个更好"
每个动作有一个效用函数:Utility = f(世界状态)
选择效用最高的动作执行
效用函数设计:
├── 线性:U = ax + b
├── 曲线:U = x^a(a<1 递减收益,a>1 递增收益)
├── Sigmoid:U = 1 / (1 + e^(-x))(阈值行为)
└── 分段:不同区间不同函数
```
### 效用系统示例:生存游戏 AI
```python
# 效用函数定义
actions = {
'eat_food': {
'hunger_utility': lambda h: 1 - h/100, # 越饿越想吃
'food_available': lambda inv: 1 if inv.food > 0 else 0,
'total': lambda h, inv: (1 - h/100) * (1 if inv.food > 0 else 0)
},
'find_shelter': {
'weather_utility': lambda w: 0.9 if w.storm else 0.1,
'night_utility': lambda t: 0.8 if t > 18 else 0.0,
'health_utility': lambda hp: 1 - hp/100,
'total': lambda w, t, hp: max(w, t, hp * 0.5)
},
'hunt': {
'hunger_utility': lambda h: h/100,
'weapon_utility': lambda inv: 0.9 if inv.weapon else 0.1,
'energy_utility': lambda e: e/100,
'total': lambda h, inv, e: (h/100) * (0.9 if inv.weapon else 0.1) * (e/100)
}
}
# 每帧评估
best_action = max(actions, key=lambda a: a['total'](world_state))
```
### Utility AI 高级特性
| 特性 | 说明 | 应用 |
|------|------|------|
| **衰减** | 上次执行的动作效用暂时降低 | 避免行为切换过快 |
| **群体效用** | 考虑其他 AI 的选择 | 分散行为避免扎堆 |
| **随机扰动** | 添加小幅随机噪声 | 增加行为多样性 |
| **多层选择** | 先选策略,再选具体动作 | 减少每帧计算量 |
---
## 群体 AI 与涌现行为
### Boids 算法
```python
# Craig Reynolds Boids (1986)
class Boid:
def update(self, neighbors):
separation = self.separate(neighbors) # 避免碰撞
alignment = self.align(neighbors) # 朝向一致
cohesion = self.cohere(neighbors) # 向中心聚集
# 加权组合
self.velocity += (separation * 1.5 +
alignment * 1.0 +
cohesion * 1.0)
self.position += self.velocity
# 参数效果
SEPARATION_WEIGHT = 1.5 # 高 → 松散群体,低 → 密集群体
ALIGNMENT_WEIGHT = 1.0 # 高 → 整齐移动,低 → 混乱
COHESION_WEIGHT = 1.0 # 高 → 紧密跟随,低 → 分散
NEIGHBOR_RADIUS = 50 # 感知范围
```
### 群体编队
| 阵型 | 实现方式 | 游戏案例 |
|------|----------|----------|
| **跟随领导** | 每个单位跟随指定路径点 | RTS 行军 |
| **网格阵型** | 预定义相对偏移位置 | 全面战争 |
| **楔形** | 前方 1 个,后方扇形展开 | 战斗机编队 |
| **包围圈** | 围绕目标均匀分布 | 怪物围攻 |
| **散兵线** | 横向展开,前后错落 | 射击游戏 |
---
## 感知与信息模型
### 感官系统
```
AI 感知模型:
视觉(Vision)
├── 视锥检测(View Frustum)
│ └── 角度、距离、遮挡(Raycast)
├── 注意力机制
│ └── 动态物体优先、声音方向提示
└── 记忆衰减
└── 目标离开视野后保留 N 秒
听觉(Hearing)
├── 声音事件(枪声、脚步声、爆炸)
├── 传播范围(距离衰减)
└── 方向估计(可能不准确)
触觉(Touch)
├── 碰撞检测
└── 伤害来源方向
社交(Social)
├── 同伴呼叫(发现敌人时通知)
└── 状态同步(共享警觉等级)
```
### 信息层级
| 层级 | 信息确定性 | 行为影响 | 示例 |
|------|-----------|----------|------|
| **确认** | 100% | 主动攻击 | 视野内清晰看到 |
| **怀疑** | 60% | 调查 | 听到声音、看到影子 |
| **警戒** | 30% | 准备状态 | 同伴警报、环境异常 |
| **正常** | 0% | 日常行为 | 无异常信息 |
---
## 机器学习在游戏 AI 中的应用
### ML 技术适用场景
| 技术 | 适用场景 | 挑战 |
|------|----------|------|
| **强化学习(RL)** | 复杂策略游戏、机器人控制 | 训练时间长、不可解释 |
| **行为克隆** | 模仿人类玩家行为 | 需要大量标注数据 |
| **进化算法** | 平衡性调优、NPC 参数 | 评估函数设计困难 |
| **神经网络** | 图像识别(目标检测)、自然语言 | 运行时性能、可预测性 |
### AlphaStar / OpenAI Five 启示
```
《星际争霸2》AlphaStar 特点:
- APM 限制在 human-level(<300)
- 多智能体训练(不同策略种群)
- 人口训练(Population-based Training)
《Dota2》OpenAI Five 特点:
- 完整 5v5 团队协作
- 奖励塑造(Reward Shaping)关键
- 从随机到世界冠军:约 180 年游戏时间等效训练
应用限制:
- 训练成本极高(数百万美元)
- 仅适用于规则稳定、可模拟的环境
- 行为不可预测,难以调试
```
### 实用 ML 方案
```
小规模 ML 在游戏中的实际应用:
1. 难度动态调整
└── 输入:玩家近期表现数据
└── 模型:简单回归或决策树
└── 输出:下一关难度参数
2. 玩家行为预测
└── 预测:玩家接下来可能做什么
└── 应用:预加载资源、AI 提前准备
3. 异常检测
└── 检测:作弊行为模式
└── 模型:无监督聚类
4. 内容推荐
└── 推荐:关卡/装备/技能
└── 模型:协同过滤
```
---
## 三大引擎 AI 工具对比
| 功能 | Unity | Unreal Engine | Godot |
|------|-------|---------------|-------|
| **内置 NavMesh** | ✅ NavMesh | ✅ Recast/Detour | ✅ NavigationServer |
| **行为树插件** | ✅ Behavior Designer | ✅ Behavior Tree | ❌ 需第三方 |
| **状态机工具** | ✅ Animator FSM | ✅ State Machine | ✅ AnimationTree |
| **感知系统** | ❌ 需自写 | ✅ AI Perception | ❌ 需自写 |
| **RVO 避障** | ✅ A* Pathfinding Project | ✅ RVO2 | ❌ 需第三方 |
| **ML 工具** | ✅ ML-Agents | ✅ Learning Agents | ❌ 不成熟 |
| **可视化调试** | ✅ Gizmos | ✅ AI Debug | ✅ 基础 |
---
## 经典案例分析
### F.E.A.R. — GOAP 标杆
```
设计亮点:
- 敌人自动规划战术动作
- 可理解的行为(玩家看到 AI 在"思考")
- 动态环境利用(踢翻桌子做掩体)
- 小队协调(掩护、侧翼、撤退)
规划动作库:
├── 攻击(Attack)→ 前提: 有武器, 看到目标
├── 寻找掩体(TakeCover)→ 效果: 在掩体后
├── 侧翼移动(Flank)→ 效果: 目标侧后方
├── 投掷手雷(ThrowGrenade)→ 前提: 有手雷, 目标在掩体后
└── 呼叫支援(CallBackup)→ 前提: 有通讯设备
```
### 光环系列 — 战斗对话系统
| 设计 | 实现 | 效果 |
|------|------|------|
| **状态广播** | AI 大声喊出当前状态 | 玩家理解 AI 意图 |
| **反应对话** | 对玩家行为即时回应 | 增强沉浸感 |
| **小队通讯** | 敌人之间喊话协调 | 感觉 AI 在配合 |
| **情绪变化** | 从嚣张到恐慌 | 反馈玩家威胁度 |
### 《全面战争》—— 群体战术 AI
```
战役 AI 层级:
├── 战略层(Strategic)
│ └── 目标选择:攻哪座城、结盟/开战
├── 战役层(Campaign)
│ └── 军队调度:行军路线、集结点
└── 战术层(Tactical)
└── 战场指挥:阵型、冲锋时机、骑兵迂回
战术决策:
- 评估敌我兵力比 → 决定进攻/防守/撤退
- 地形分析 → 高地、森林、河流利用
- 兵种克制 → 骑兵绕后、矛兵抗线、弓箭远程
```
### Left 4 Dead — AI Director
```
AI Director 核心循环:
1. 监测玩家压力水平(受伤、弹药、进度速度)
2. 动态生成感染者:
- 压力低 → 生成更多敌人
- 压力高 → 生成较少,给予恢复时间
3. 特殊感染者投放时机:
- 玩家在开阔地 → 生成 Hunter
- 玩家聚集 → 生成 Boomer
- 玩家推进快 → 生成 Tank 阻挡
4. 物品放置:
- 根据玩家需求动态调整(缺弹药给弹药)
5. 音乐与环境:
- 紧张音乐配合生成节奏
```
---
## 性能优化指南
| 优化策略 | 具体方法 | 预期收益 |
|----------|----------|----------|
| **分层更新** | 远处 AI 低频更新(1-5Hz) | 50-80% CPU 节省 |
| **睡眠机制** | 不可见/无事件 AI 暂停 | 大量空闲 AI 零开销 |
| **空间分区** | 网格/四叉树减少邻居查询 | O(n) → O(log n) |
| **路径缓存** | 缓存常见路径 | 减少重复计算 |
| ** LOD AI** | 远处 AI 简化决策 | 减少行为树深度 |
| **批量评估** | 群体行为统一计算 | 缓存友好 |
---
## 最佳实践清单
- [ ] **从简单开始**:FSM → 行为树 → GOAP/Utility,逐步升级
- [ ] **可调试优先**:AI 决策必须可观察、可记录、可回放
- [ ] **玩家可读性**:AI 行为应有视觉/音频反馈
- [ ] **可控的不可预测**:随机性应可控、可理解
- [ ] **分层架构**:感知 → 决策 → 行动,每层独立测试
- [ ] **性能预算**:AI 每帧 CPU 占用应有明确上限
- [ ] **数据驱动**:行为参数应可配置,避免硬编码
- [ ] **人类测试**:AI 难度和趣味性最终由人类玩家评判
---
## 相关页面
- [核心机制设计](core-mechanics.md) — 战斗 AI 与机制结合
- [AI Agent 工具](agent-tools.md) — LLM 与游戏 AI 集成
- [AI 对话 Prompt](ai-dialogue-prompts.md) — 叙事 AI 与行为 AI 结合
- [多人游戏设计](multiplayer-game-design.md) — 网络同步与 AI