Files
kunpocc-behaviortree/docs/BehaviorTree.md
2025-09-28 18:43:59 +08:00

252 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 硬核游戏开发 - 使用BehaviorTree实现游戏AI决策的开发详解
## 🎮 一个让策划抓狂的Bug
> "这个BOSS太蠢了它明明看到玩家了为什么还在那里发呆"
这是我在某公司实习时听到最多的一句话。那是一个魔幻RPG项目我负责实现一个"智能"的龙王BOSS。按照策划的设计文档这个BOSS应该能够
- 🔍 **侦察阶段**:在玩家进入领域前巡逻,警戒四周
- ⚔️ **战斗阶段**:发现玩家后立即进入战斗状态,根据距离选择近战或远程攻击
- 🩸 **血怒阶段**血量低于30%时进入狂暴模式,攻击力翻倍
- 🛡️ **防御阶段**:受到大量伤害时短暂防御,恢复少量血量
- 💨 **逃跑阶段**:血量极低时尝试逃跑,寻找掩体
听起来很简单对吧?我天真地用了一堆 `if-else` 语句:
```javascript
function updateBoss() {
if (boss.hp < 0.1 * boss.maxHp) {
if (canEscape()) {
escape();
} else if (canDefend()) {
defend();
} else {
attack();
}
} else if (boss.hp < 0.3 * boss.maxHp) {
if (playerInRange()) {
berserkerAttack();
} else {
moveToPlayer();
}
} else if (playerDetected()) {
if (playerDistance() < 5) {
meleeAttack();
} else {
rangedAttack();
}
} else {
patrol();
}
}
```
**结果?** 一场灾难!
- BOSS经常在攻击和防御之间疯狂切换
- 有时候明明发现了玩家,却突然开始巡逻
- 血怒状态下居然还会尝试逃跑
- 最要命的是:每次策划要求调整优先级,我都要重写整个逻辑!
三个通宵后我的代码变成了一个800行的意大利面条连我自己都看不懂了。更糟糕的是每次修复一个bug就会产生三个新bug。
**直到我遇到了行为树...**
一周后同样的BOSS逻辑我用行为树重新实现了
```
龙王BOSS行为树
根节点(优先选择器)
├── 逃跑分支(血量 < 10%
│ ├── 寻找掩体
│ └── 快速移动
├── 防御分支(受到重击)
│ ├── 播放防御动画
│ └── 恢复少量血量
├── 血怒分支(血量 < 30%
│ ├── 进入狂暴状态
│ └── 疯狂攻击
├── 战斗分支(发现玩家)
│ ├── 距离判断
│ ├── 近战攻击 OR 远程攻击
│ └── 追击玩家
└── 巡逻分支(默认行为)
├── 沿路径移动
└── 警戒四周
```
**奇迹发生了!**
- ✅ BOSS行为逻辑清晰优先级明确
- ✅ 策划可以直接看懂并提出修改意见
- ✅ 新增行为只需要添加新分支,不影响现有逻辑
- ✅ 调试时可以清楚看到每一步的决策过程
- ✅ 代码从800行缩减到200行可读性提升10倍
更重要的是,当策划说"能不能让BOSS在血量50%时召唤小怪"时我只需要在行为树中插入一个新分支5分钟搞定
---
**这就是行为树的魅力。**
作为一名游戏开发者你是否也遇到过类似的问题当游戏中的怪物、NPC需要表现出复杂行为时——巡逻、追击、逃跑、施法、观察环境并做出判断——背后往往不应该是一条又一条 if-else 的堆叠,而是一套清晰、可扩展、可调试的决策框架:**行为树Behavior Tree**。
本指南将带你从零开始认识行为树,让你也能构建出让策划赞不绝口的游戏 AI 决策系统!
## 一、开篇
行为树是一种用于描述 AI 决策逻辑的树形结构由根节点驱动组合节点如「选择器」「序列」负责控制流程装饰节点用于修饰行为叶子节点则执行具体动作或进行条件判断。相较有限状态机FSM行为树更易组合与复用能自然表达“尝试 A 否则 B”“按顺序执行直到成功”等复杂模式并且非常适合可视化编辑与热更新。
## 二、行为树执行流程 - 一个哥布林的日常决策
想象一下,你是一只聪明的哥布林守卫,正在洞穴门口值班。每一秒钟,你的大脑都在运转着一套复杂的决策系统——这就是行为树!
### 1. 三种人生状态(节点状态)
就像人生一样,行为树中的每个节点都只有三种可能的状态:
* **成功** ✅ - "太好了!任务完成!"
* **失败** ❌ - "唉,这条路走不通..."
* **运行中** ⏳ - "别催,我还在努力呢!"
这就像你在思考"今晚吃什么"时的状态:要么想到了(成功),要么放弃了(失败),要么还在纠结中(运行中)。
### 2. 决策节点大家族 - 每个都有自己的性格
#### 2.1 选择节点 - "备胎专家"
**性格特点**永不放弃的乐观主义者总是有Plan B、Plan C...
想象你是个饿肚子的哥布林,面前有三个选择:
1. 去厨房找剩菜
2. 去花园抓虫子
3. 啃树皮充饥
选择节点就像一个不死心的你:
- 先试试厨房有没有剩菜(第一个子节点)
- 如果厨房空空如也(失败),那就去花园抓虫子(第二个子节点)
- 虫子也没有?那就啃树皮吧(第三个子节点)
- 只要有一个成功了,选择节点就满意地说:"搞定!"
**执行规则**
```
从左到右挨个试:
✅ 子节点成功 → "太好了!" → 选择节点成功
❌ 子节点失败 → "下一个!" → 继续尝试
⏳ 子节点运行中 → "等等..." → 选择节点也运行中
```
#### 2.2 顺序节点 - "完美主义者"
**性格特点**:严格按计划执行,一步都不能错
还是那只饿肚子的哥布林,但这次你决定做一顿大餐:
1. 先洗手
2. 然后准备食材
3. 接着开火做饭
4. 最后享用美食
顺序节点就像一个强迫症患者:
- 必须先洗手,洗不干净就不继续
- 洗手成功了,才能准备食材
- 食材准备好了,才能开火
- 任何一步失败,整个计划泡汤!
**执行规则**
```
严格按顺序来:
✅ 子节点成功 → "很好,下一步!" → 继续执行
❌ 子节点失败 → "完蛋了!" → 顺序节点失败
⏳ 子节点运行中 → "慢慢来..." → 顺序节点等待
```
#### 2.3 行为节点 - "实干家"
**性格特点**:话不多说,撸起袖子就是干
这是真正干活的节点,比如:
- "巡逻10秒钟"
- "攻击敌人"
- "播放死亡动画"
行为节点就像一个靠谱的员工,给它一个任务,它会:
- 立即开始执行(返回"运行中"
- 完成后汇报结果("成功"或"失败"
- 有些任务需要时间,会持续返回"运行中"
#### 2.4 条件节点 - "侦察兵"
**性格特点**:眼观六路,耳听八方,专门负责收集情报
条件节点就像哨兵,负责观察环境:
- "敌人在视野内吗?"
- "血量低于30%吗?"
- "身上有钥匙吗?"
它们动作很快,瞬间给出答案:要么"是"(成功),要么"不是"(失败),没有"也许"。
### 3. 一个完整的哥布林决策故事
让我们看看一只哥布林守卫的完整思考过程:
```
哥布林的行为树:
根节点(选择)
├── 战斗分支(顺序)
│ ├── 条件:发现敌人?
│ ├── 行为:冲向敌人
│ └── 行为:攻击
├── 巡逻分支(顺序)
│ ├── 条件:在巡逻路径上?
│ └── 行为:继续巡逻
└── 待机分支
└── 行为:原地等待
```
**执行过程**
1. **第一轮思考**
- 选择节点:"让我看看该做什么..."
- 尝试战斗分支 → 检查"发现敌人?" → 没有敌人(失败)
- 尝试巡逻分支 → 检查"在巡逻路径上?" → 是的(成功)→ 开始巡逻(运行中)
2. **第二轮思考**(巡逻进行中):
- 选择节点:继续之前的决策
- 巡逻分支:巡逻还在进行中...
3. **第三轮思考**(突然发现敌人):
- 选择节点:重新评估
- 尝试战斗分支 → "发现敌人?" → 有敌人!(成功)→ 冲向敌人(运行中)
这就是行为树的魅力:每一帧都在重新评估,动态调整策略,就像一个真正在思考的智能体!
### 4. 可视化流程图 - 让抽象变具体
看完了哥布林的故事,让我们用更直观的方式来理解行为树的执行过程。
#### 4.1 一颗简单的行为树结构
![image](../image/maunal/flow.png)
这就是我们刚才讲的哥布林决策树的可视化版本。每个方块代表一个节点,箭头表示执行流向。
#### 4.2 执行流程的"心跳"
行为树就像一颗跳动的心脏每一帧通常是1/60秒都会从根节点开始"心跳"一次:
![image](../image/maunal/flow2.png)
**执行流程就像这样**
1. **心跳开始** - 从根节点开始
2. **向下探索** - 根据节点类型决定如何执行子节点
3. **状态回传** - 叶子节点的结果层层向上传递
4. **等待下次心跳** - 一帧结束,等待下一帧继续
这种"心跳式"的执行方式让AI能够
- 🔄 **实时响应**:每帧都重新评估环境
- 🎯 **优先级明确**:重要的行为总是先被考虑
- 🔧 **易于调试**:可以清楚看到每一步的决策过程
- 🚀 **性能友好**:只执行必要的节点,避免浪费
> **小贴士**:想象行为树就像一个永不疲倦的大脑,每一瞬间都在问自己:"现在最应该做什么?"然后立即行动!