一、峡谷里的"演员":谁在控制它们
"小陈,峡谷里除了玩家控制的英雄,还有小兵、野怪、防御塔——它们是谁在控制?"老周问。
"AI?"
"对,游戏 AI(Artificial Intelligence)——不过这里的 AI 不是 ChatGPT 那种'智能',是一系列规则脚本,让非玩家角色(NPC)表现出'像人一样'的行为。"
MOBA 里的 AI 角色:
小兵(Minion):沿着兵线推进,攻击遇到的敌人
野怪(Monster):在野区巡逻,被攻击后反击
防御塔(Tower):攻击进入射程的敌人
泉水/基地:自动恢复、自动出小兵
每种 AI 的"行为规则"不同:
小兵:跟着兵线走 → 遇到敌人 → 攻击 → 没血就死
野怪:在出生点附近徘徊 → 被打 → 反击 → 脱战回血
塔 :固定位置 → 敌人进射程 → 锁定攻击
"游戏 AI 的本质:'感知 → 决策 → 行动'的循环——每帧看周围情况(感知),决定做什么(决策),然后执行(行动)。规则写得越细,角色看起来越'聪明'。"
二、有限状态机 AI:最简单也最常用
"最简单的 AI 框架:有限状态机(FSM, Finite State Machine)。"老周说,"还记得第四章的动画状态机吗?同一个思想。"
小兵的有限状态机:
┌──────────┐ 到兵线终点/遇到塔 ┌──────────┐
│ 前进 Walk │ ──────────────────▶ │ 攻击 Attack│
└──────────┘ └──────────┘
▲ │
│ 目标死亡/脱离 │
│ ▼
│ ┌──────────┐
└─────────────────────────────│ 待机 Idle │
附近没有敌人 └──────────┘
每个状态有"进入/更新/退出"逻辑
状态间靠"条件"跳转
小兵 AI 伪代码:
class MinionAI:
def update(self):
if self.state == "walk":
self.move_along_lane()
if self.find_enemy_in_range():
self.change_state("attack")
elif self.state == "attack":
self.attack(self.target)
if not self.target.is_alive():
self.change_state("walk")
"FSM 是游戏 AI 的第一课——状态少、逻辑简单、容易调试。小兵、野怪、塔用 FSM 完全够。但复杂角色(BOSS 多阶段技能)状态多了会乱,就需要更高级的框架。"
三、行为树:更高级的 AI 框架
"状态多了以后,FSM 会变成'意大利面条'。这时候用行为树(Behavior Tree)。"老周说:
行为树(Behavior Tree):
用树状结构组织 AI 行为,从根节点向下"决策"
野怪的行为树:
┌ 选择(Selector:挑一个优先级最高的行为)
├── ▶ 逃跑:血量 < 20% 且被追击
├── ▶ 反击:正在被攻击
├── ▶ 巡逻:没有敌人
└── ▶ 待机:兜底
┌ 节点类型 ┐
│ 选择器 Selector:试子节点,第一个成功就返回 │
│ 顺序器 Sequence:全部成功才算成功 │
│ 条件节点:判断(如"血量 < 20%") │
│ 行动节点:执行动作(如"向家移动") │
└──────────┘
好处:
比 FSM 直观(一眼看清决策逻辑)
可复用(子行为树可嵌套)
策划也能看懂、能调
"行为树是商业游戏 AI 的主流框架(Unity 有 Behavior Designer 插件,Unreal 内置)。野怪、BOSS、NPC 队友,都用它。FSM 管'简单角色',行为树管'复杂角色'。"
四、A* 寻路:怎么绕过障碍走到目标
"AI 光会决策还不行,还要会走路——从 A 点走到 B 点,绕过墙和障碍。这就是寻路(Pathfinding),最经典的是 A* 算法。"老周说:
A* 寻路(A-star):
把地图划分成格子(网格)或导航网格(NavMesh)
从起点开始,评估每个格子到终点的"代价"
一步步找出一条"最短路径"
┌──┬──┬──┬──┬──┐
│起 │ │ │ │ │
├──┼──┼──┼──┼──┤
│ │▓▓│▓▓│ │ │ ▓ = 障碍(墙)
├──┼──┼──┼──┼──┤
│ │▓▓│ │ │ │ → = 找到的路径
├──┼──┼──┼──┼──┤
│→→│→→│→→│→ │ │
├──┼──┼──┼──┼──┤
│ │ │ │→ │终│
└──┴──┴──┴──┴──┘
A* 核心公式:
F = G + H
G = 从起点到当前格子的实际代价
H = 从当前格子到终点的估算代价(启发式)
优先扩展 F 最小的格子 → 保证找到最优路径
工程上:用 Unity 的 NavMesh(导航网格烘焙)
不用手写 A*,但要知道原理
(面试常问:A* 的 G 和 H 是什么?)
# A* 的骨架(理解用)
def a_star(start, goal, grid):
open_set = {start} # 待探索
came_from = {} # 记录路径
g_score = {start: 0}
while open_set:
current = min(open_set, key=lambda p: g_score[p] + heuristic(p, goal))
if current == goal:
return reconstruct_path(came_from, current) # 找到路径
open_set.remove(current)
for neighbor in grid.neighbors(current):
tentative = g_score[current] + 1
if tentative < g_score.get(neighbor, inf):
came_from[neighbor] = current
g_score[neighbor] = tentative
open_set.add(neighbor)
return [] # 无路可走
"A* 是'找路'的黄金标准——MOBA 里小兵沿着兵线走、野怪回野区、英雄点击地面移动,背后全是寻路。'点击地面,英雄绕墙走过去',就是 A* 在干活。"
五、塔的攻击逻辑:射程与锁定
"防御塔的 AI 最简单,但有几个经典细节。"老周说:
防御塔 AI 规则:
感知:扫描射程内的敌人
决策:锁定"最优先目标"(通常是最近的/攻击友军的)
行动:发射弹道,造成伤害
特殊:优先攻击"正在攻击我方英雄"的敌人(保护队友)
塔的攻击细节:
射程:攻击半径
伤害:单体高伤
冷却:攻击间隔
索敌:优先最近 / 优先低血量 / 优先攻击我方者
MOBA 经典机制(简化版可省略):
塔的"仇恨"机制——攻击谁有讲究
小兵进塔 → 塔打小兵;英雄攻击敌人 → 塔转移目标
→ 这个"仇恨逻辑"是 MOBA 对线博弈的核心
"防御塔看起来简单,但'仇恨机制'的设计直接决定了对线的体验——高手可以'塔下消耗'、'越塔强杀',全看塔的仇恨规则。这就是'简单角色 + 巧妙规则 = 深度玩法'。"
六、AI 性能与分层更新:别让 AI 拖垮游戏
"峡谷里几十个小兵 + 野怪 + 塔,如果每帧都给所有 AI 做感知决策,性能会炸。"老周说:
AI 性能优化:
① 分层更新(最常用):
- 玩家身边的 AI:每帧更新(精细)
- 远处的 AI:每 0.5 秒更新一次(粗粒度)
- 看不到的 AI:暂停更新(等进入视野)
② 感知降频:
不每帧扫描周围,隔几帧扫一次
③ 对象池:
小兵死了不是销毁,是回收复用(第十一章细讲)
④ 简化寻路:
小兵不需要完整 A*,走"预计算的兵线路径"就行
原则:AI 的"聪明"要花钱(CPU),
把预算花在玩家看得见的地方
"游戏 AI 的工程原则:'远近有别'——玩家眼前的 AI 要'聪明',远处的可以'迟钝'。把性能预算花在刀刃上,这是老游戏引擎(和手机性能)逼出来的智慧。"
七、章末:老周的第六层总结
第六层:AI 与寻路
├── 游戏 AI = 规则脚本(感知→决策→行动)
├── FSM 状态机:小兵/野怪/塔(简单角色首选)
├── 行为树:复杂角色(BOSS、队友)
├── A* 寻路:F = G + H(找最短路径,绕障碍)
│ 工程用 NavMesh,原理要懂(面试必考)
├── 塔仇恨机制:射程+索敌+保护逻辑(对线核心)
└── 性能:分层更新/降频/对象池(钱花在刀刃上)
下一章预告:
峡谷热闹了:英雄、小兵、野怪、塔都在动。
但是——这是"单机版"!
怎么让两个玩家(5v5)在同一局游戏里看到"同一个世界"?
—— 网络同步。MOBA 最硬核的一章。
"小陈,按一下 Play——峡谷活了!小兵一队队沿着兵线冲,野怪在草丛巡逻,防御塔咚咚地打,好不热闹。"老周满意地笑了,"但是,你现在是'一个人'在打'一堆电脑'。王姐要的是5v5 联网对战——两个玩家在不同手机上,看到的必须是'同一个世界'。下一章,MOBA 最硬核、也是游戏开发里最有含金量的技术:网络同步。"