🤖 有限状态机 (FSM) 设计与实战指南
文档目标: 详解 Vampirefall 中 AI 行为的核心驱动逻辑。 适用对象: 怪物 AI、防御塔逻辑、Boss 阶段转换。1. 🧠 FSM 核心概念 (The Basics)
有限状态机由三个要素组成:-
状态 (State): 角色当前在做什么? (e.g.,
Idle,Chase,Attack) -
转换 (Transition): 什么条件下切换到另一个状态? (e.g.,
Distance < 5m-> 切换到Attack) -
行为 (Action): 进入/退出/保持该状态时做什么? (e.g.,
OnEnter: 播放吼叫动画)
2. 👹 怪物 AI 状态机 (Monster FSM)
混合品类游戏的怪物 AI 比传统塔防更复杂,因为它需要处理“仇恨切换”。2.1 状态流转图 (State Graph)
2.2 关键状态详解
A. State_Move (寻路移动)
- 目标: 沿着 FlowField (流场) 或 NavMesh 走向基地。
- 特殊逻辑: 无视玩家。这是塔防怪物的特征,它们眼里只有基地。除非被“嘲讽”或受到高额伤害。
- 代码逻辑: 每 0.5秒 检测一次前方是否有
Obstacle(塔/墙)。如果有,切换到State_Breach。
B. State_Breach (拆墙)
- 场景: 怪物被塔挡住了去路,或者这是个专门拆塔的“工兵怪”。
- 逻辑: 锁定面前的塔,播放攻击动画。
- 退出条件:
- 塔炸了 -> 切回
Move。 - 玩家过来打了它一下 -> 切到
Aggro。
- 塔炸了 -> 切回
C. State_Aggro (仇恨/追击)
- 场景: ARPG 元素的核心。
- 逻辑: 暂时放弃基地,追着玩家(或嘲讽图腾)打。
- Leash (狗链) 机制: 为了防止玩家把怪风筝到地图边缘,必须设置一个
MaxAggroDistance(比如 15米) 或MaxAggroTime(比如 5秒)。超过限制强制切回Move,并且 3秒内免疫仇恨。
2.3 📁 普通怪物实战案例 (Minion Examples)
结合游戏特色,我们定义两种极端的怪物 AI 模板。案例 A: 骷髅工兵 (Skeleton Sapper) - 绝对攻城型
- 定位: 玩家的噩梦,必须优先处理。
- FSM 特异点:
- 无 Aggro 状态: 它的状态机里删除了
Aggro状态。 - 逻辑: 即使玩家拿刀砍它的头,它也绝对不回头,一心一意往基地走。
- 被动: 当
HP < 30%时,切换到Sprint(冲刺) 状态,移速翻倍。
- 无 Aggro 状态: 它的状态机里删除了
案例 B: 幽灵刺客 (Ghost Assassin) - 风筝/切后排型
- 定位: 骚扰玩家,迫使玩家走位。
- FSM 特异点:
- 新增
Flee(逃离) 状态:- 当
DistanceToPlayer < 3m(被近身) 时,触发逃离。 - 逻辑: 向
(SelfPos - PlayerPos)方向移动 2秒。
- 当
- 新增
Stealth(隐身) 状态:- 逃离结束后,进入隐身(不可被塔锁定),尝试绕后。
- 新增
3. 👑 Boss 战斗状态机 (Boss FSM)
Boss 不仅仅是血厚的怪,它是一个带有剧本的流程。我们需要引入 “Phase System” (阶段系统)。3.1 阶段转换流转图
Boss 的 FSM 是分层的:上层管理阶段,下层管理具体行为。3.2 实战案例:鲜血领主 (Vampire Lord)
Phase 1: 优雅剑术 (100% - 60% HP)
- 行为模式: 类似于强力精英怪。
- 状态池:
Slash: 前方扇形斩击。Thrust: 针对仇恨目标的快速突刺。SummonBats: 召唤 2 只小蝙蝠骚扰。
- 转换条件:
HP < 60%-> 触发State_Vanish(消失)。
Transition 1: 鲜血盛宴 (机制检测)
- 行为:
- Boss 变为不可选中,瞬移到大厅中央悬空。
- 场地四周生成 4 个 [血茧]。
- 血茧会缓慢向 Boss 移动,如果碰到 Boss,每吃一个回血 10%。
- 玩家目标: 在血茧碰到 Boss 前打爆它们。
- 结束: 所有血茧被毁或被吃 -> 进入 Phase 2。
Phase 2: 魔法轰炸 (60% - 20% HP)
- 行为模式: 站桩法师,高频 AOE。
- 状态池:
BloodRain: 地面随机生成红圈,2秒后爆炸。LaserSweep: 旋转激光扫射全场,玩家必须跟着转或用无敌帧穿过。
- 转换条件:
HP < 20%-> 触发State_Enrage(吼叫动画)。
Phase 3: 困兽之斗 (20% - 0% HP)
- 行为模式: 疯狗模式 (DPS Check)。
- 状态:
- 移速 +100%,攻速 +50%。
- 不再释放远程技能,单纯地追着玩家平 A。
- 软狂暴: 每过 10秒,攻击力叠加 10%。强迫玩家尽快击杀。
4. 🗼 防御塔状态机 (Tower FSM)
塔的逻辑相对简单,重点在于“索敌效率”和“状态重置”。3.1 状态流转图
3.2 关键状态详解
A. State_Idle (待机扫描)
- 性能优化: 不要每帧
Update里都去Physics.OverlapSphere。 - 最佳实践: 使用 协程 或 Timer,每 0.1秒 - 0.2秒 扫描一次。或者让怪物进入射程时主动触发塔的 Trigger。
B. State_Warmup (预热/瞄准)
- 场景: 激光塔需要蓄力,或者炮塔需要旋转炮口对准目标。
- 逻辑:
TurretHead.LookAt(Target)。- 如果是激光塔,播放“嗡嗡嗡”的音效和光效。
- 如果目标跑出了射程,切回
Idle(浪费了蓄力)。
C. State_Fire (开火)
- 逻辑:
- 生成子弹 (从对象池)。
- 播放后坐力动画。
- 瞬间切入
State_Cooldown。不要停留在 Fire 状态。
4. 💻 代码实战:轻量级 FSM 框架 (No-GC)
不要用复杂的类继承 (Class-based States) 来做成千上万的小怪,那样内存开销太大。 推荐使用 Enum + Switch (简单怪) 或 Struct-based FSM (复杂怪)。4.1 方案 A: 极简版 (适合小怪/塔)
4.2 方案 B: 结构化版 (适合 Boss/玩家)
如果你嫌 Switch 太乱,可以用轻量级的类封装,但要避免每帧new。
5. 🎓 实用建议与坑
5.1 🚫 避免 “Ping-Pong” (状态乒乓)
- 现象: 怪物在
Move和Attack之间疯狂切换,每帧切一次,导致动画鬼畜。 - 原因: 攻击距离判定太死。进入 5.0m 攻击,退出 5.0m 移动。
- 解法: 迟滞 (Hysteresis)。
- 进入攻击状态阈值:
Distance < 5.0m - 退出攻击状态阈值:
Distance > 6.0m - 留出 1.0m 的缓冲区。
- 进入攻击状态阈值:
5.2 🌍 全局状态 (Global State)
- 有些状态是凌驾于 FSM 之上的,比如 CC (控制)。
- 不要把
Stunned(眩晕) 做成一个普通状态。 - 做法:
Stunned是一个 Bool 标记。在Update()的最开头检查:
5.3 🎞️ 动画状态机 (Animator) vs 逻辑状态机 (Logic FSM)
- 原则: Logic FSM 驱动 Animator,绝反之。
- 错误: 在 Animator 的
OnStateExit里写代码改逻辑变量。这会导致逻辑很难调试。 - 正确: 代码里
ChangeState(Attack)-> 调用animator.SetTrigger("Attack")。