鸿蒙游戏 AI NPC:行为树原理 + 实战代码
大家好,我是子玥酱,一名长期深耕在一线的前端程序媛 👩💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。
我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括前端工程化、小程序、React / RN、Flutter、跨端方案,
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。
技术方向:前端 / 跨端 / 小程序 / 移动端工程化
内容平台:掘金、知乎、CSDN、简书
创作特点:实战导向、源码拆解、少空谈多落地
文章状态:长期稳定更新,大量原创输出
我的内容主要围绕前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读展开。文章不会停留在“API 怎么用”,而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。
子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取11 类前端进阶学习资源(工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学“明白”,也用“到位”
持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱
文章目录
- 引言
- 一、什么是行为树?
- 二、为什么游戏都在用行为树?
- 三、行为树的三大节点
- Selector(选择器)
- Sequence(顺序器)
- Action(动作节点)
- 四、设计一个简单 NPC
- 五、定义行为树节点
- 六、实现 Action 节点
- 七、实现 Selector
- 八、加入条件节点
- 九、实现追击逻辑
- 十、AISystem 驱动行为树
- 十一、与 Store 结合
- 十二、Boss 行为树实战
- 十三、为什么行为树比 if-else 更强?
- 十四、行为树与多端同步
- 十五、未来升级:行为树 + AI Agent
- 十六、一个关键认知升级
- 总结
引言
很多开发者第一次给鸿蒙游戏加 NPC 时,都会这样写:
if(playerNear){attack()}或者:
if(hp<30){runAway()}刚开始感觉没问题:
能跑 能打 能追人但随着游戏复杂度增加:
巡逻 追击 攻击 释放技能 逃跑 求援 Boss机制很快就会出现一个问题:
if-else 地狱。
代码可能变成:
if(playerNear){if(hp>50){if(skillReady){castSkill()}else{attack()}}else{if(friendNear){callHelp()}else{runAway()}}}几个月后连自己都不敢改,很多人会觉得:
是不是 AI 太复杂了?
其实不是,问题在于:
你在用条件判断实现决策系统。
而现代游戏普遍采用:
Behavior Tree (行为树)来驱动 NPC。
一、什么是行为树?
先看一个最简单的 NPC,需求:
发现玩家 ↓ 攻击玩家传统写法:
if(canSeePlayer()){attack()}没问题,但增加需求:
发现玩家 ↓ 距离近 ↓ 攻击 距离远 ↓ 追击逻辑开始复杂,行为树则表示为:
发现玩家? ↓ 是 ↓ 距离是否足够? ↓ ↓ 是 否 ↓ ↓ 攻击 追击本质上:
行为树是一种可视化决策流程。
二、为什么游戏都在用行为树?
因为 NPC 本质上就是:
不断决策例如,怪物:
巡逻 发现敌人 追击 攻击 逃跑Boss:
一阶段 二阶段 狂暴阶段 释放技能 召唤小怪这些本质都是:状态选择问题,行为树非常适合处理。
三、行为树的三大节点
最常见的是:
Selector Sequence ActionSelector(选择器)
意思:
从左到右尝试 成功一个就结束例如:
攻击 ↓失败 追击 ↓失败 巡逻表现:
优先攻击 其次追击 最后巡逻Sequence(顺序器)
意思:
全部成功才算成功例如:
发现玩家 ↓ 接近玩家 ↓ 攻击任何一步失败:
整个流程失败Action(动作节点)
真正执行行为,例如:
Attack Move Patrol RunAway四、设计一个简单 NPC
需求:
发现玩家 ↓ 攻击 否则 ↓ 巡逻行为树:
Selector ├── AttackPlayer └── Patrol对应结构:
root=Selector(AttackPlayer(),Patrol())五、定义行为树节点
基础接口:
enumNodeStatus{Success,Failure,Running}interfaceBTNode{tick():NodeStatus}所有节点统一:
tick()驱动。
六、实现 Action 节点
巡逻:
classPatrolNodeimplementsBTNode{tick():NodeStatus{console.info('Patrol')returnNodeStatus.Success}}攻击:
classAttackNodeimplementsBTNode{tick():NodeStatus{console.info('Attack')returnNodeStatus.Success}}七、实现 Selector
核心逻辑:
classSelectorNodeimplementsBTNode{constructor(privatechildren:BTNode[]){}tick():NodeStatus{for(constnodeofthis.children){constresult=node.tick()if(result===NodeStatus.Success){returnresult}}returnNodeStatus.Failure}}作用:
优先执行最重要行为八、加入条件节点
例如:
发现玩家?判断,实现:
classSeePlayerNodeimplementsBTNode{constructor(privatenpc:NPC){}tick():NodeStatus{returnthis.npc.canSeePlayer()?NodeStatus.Success:NodeStatus.Failure}}九、实现追击逻辑
需求:
发现玩家 ↓ 追击 ↓ 攻击行为树:
Sequence ├── SeePlayer ├── MoveToPlayer └── Attack代码:
constcombatTree=newSequenceNode([newSeePlayerNode(npc),newMoveNode(npc),newAttackNode(npc)])十、AISystem 驱动行为树
前面我们讲过:
Store System HUD架构,行为树应该属于:
AISystem而不是:
UI例如:
classAISystem{update(npc:NPC){npc.behaviorTree.tick()}}十一、与 Store 结合
NPC状态:
classNPCStore{hp=100targetId=0position={x:0,y:0}}行为树读取:Store 决策。
然后:
AISystem修改:
Store状态,形成:
Store ↓ BehaviorTree ↓ AISystem ↓ Store闭环。
十二、Boss 行为树实战
Boss需求:
HP > 50% 普通攻击 HP < 50% 释放大招 HP < 20% 狂暴模式行为树:
Selector ├── RageMode ├── UltimateSkill └── NormalAttack代码:
Selector(RageNode(),UltimateNode(),AttackNode())结构非常清晰。
十三、为什么行为树比 if-else 更强?
传统:
if()if()if()if()最终:
无法维护行为树:
节点化 可组合 可扩展增加新行为:
SkillNode插入即可,无需重写全部逻辑。
十四、行为树与多端同步
前面我们讲:
Store一致 System一致才能实现:
多端一致性行为树天然符合,因为:
输入一致 ↓ 行为树一致 ↓ 决策一致 ↓ 状态一致例如:
手机NPC PC NPC执行同一行为树,结果相同。
十五、未来升级:行为树 + AI Agent
未来 NPC 不再只是:
固定规则而是:
行为树 + 大模型例如:
行为树 负责框架 LLM 负责决策结构:
Selector ↓ AskLLM() ↓ Attack Move Trade TalkNPC 会变得更加智能。
十六、一个关键认知升级
初学者认为:
AI = if-else进阶开发者认为:
AI = 行为树而大型项目最终理解:
行为树不是 AI,而是管理 AI 决策复杂度的架构。
因为真正的问题从来不是:
NPC会不会攻击而是:
当NPC拥有100种行为时 系统还能不能维护总结
鸿蒙游戏中的 AI NPC 推荐架构:
Store ↓ BehaviorTree ↓ AISystem ↓ Store核心节点:
Selector Sequence Action核心优势:
逻辑清晰 可视化 易扩展 易测试 支持多端同步如果用一句话总结:
行为树的本质,不是让 NPC 更聪明,而是让复杂 AI 行为变得可管理、可组合、可扩展。
