想象你是一位身经百战的主厨,周六要为十二位客人筹备一场晚宴。你并没有照着一本流水账菜谱机械操作,而是先在脑中立下一个总目标——“让宾客满意”,然后把目标拆解成“备料→烹饪→上菜”三大环节,每个环节继续细化,直到出现“洗菜、切肉、调酱”这类立刻能动手的具体动作。你一边拆解,一边检查冰箱和灶台:食材够吗?烤箱预热了吗?如果缺了某样东西,就换一种做法,重新编排局部工序。最后,你排出一张当日的执行清单。这套“从目标出发、层层拆解、动态排程”的思考方式,正是本文的主角——HTN层次化任务网络(Hierarchical Task Network)。它让游戏里的NPC不再背死剧本,而是像一位真正的主厨那样,临场制定计划、随机应变。

岗位关联

掌握HTN,意味着你从“给NPC写死剧本”进阶到“教会NPC自己排计划”——这是游戏AI工程师的核心竞争力,也是面试中的高频考点。

目录
  1. 可视化演示
  2. 从目标到计划:HTN基本思路
  3. 世界的说明书:领域与任务
  4. 规划算法流程
  5. 传统行为树对比
  6. 实时重构与优化
  7. 实战案例与工具
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

演示HTN层次化任务网络:将高层任务递归分解为子任务直至原子动作,通过任务网络规划实现NPC行为的层次化决策。

本节配有交互动效(进入视口后自动加载,约 3KB)。

任务分解 任务 方法 task→sub 高层任务递归分解为子任务

从目标到计划:HTN基本思路

想象你是一位久经沙场的主厨,周六要办一场十二人的晚宴。你没有背一本死板的流水账菜谱,而是先在脑海里立下一个总目标:“让宾客满意地离开”。继而,这个目标自然浮现出三个环节——备料、烹饪、上菜;每个环节又继续细化,直到出现“洗菜、切肉、调酱”这些立刻能下手的动作。整个过程像剥洋葱,一层、两层、三层,最后露出可以下锅的菜叶。

游戏里的NPC经常要执行类似的任务。过去,我们给NPC写死一串动作;而HTN(Hierarchical Task Network,层次化任务网络)换了一个思路:只告诉NPC“目标是什么”,由它像主厨一样自己把目标一层层拆开。拆出来的不只是简单的清单,而是一张“任务网络”——每一步和每一步之间可能存在先后、并行或互斥的关系。

在HTN里,规划器维护的这张网叫任务网络(Task Network),数学上用一个二元组描述:TN=(T,C)。T是任务节点的集合,C是约束的集合。任务分为复合任务和原子任务:复合任务是“还没想好怎么做”的抽象目标,原子任务是“可以直接执行”的动作。HTN规划器的全部工作,就是不断拿复合任务去匹配领域里预定义的方法,把它替换成子任务,直到任务网络里只剩原子任务——这时的网络就是一份可执行的计划。

所以HTN的主厨并不是在背剧本,而是在画一张动态的“作战地图”。目标在最上面,往下层层展开,网络中的每一条连线都记录着主厨对工序的思考。这就是HTN与生俱来的优雅:只要目标不变,计划永远可以从头再来。

TN=( T, C )\displaystyle TN = (\,T,\ C\,)
任务网络是一张“待办事项关系图”:节点是任务,连线是约束。HTN规划的本质,就是不断把抽象节点替换成更具体的子节点。
  1. T(任务集合)任务网络里的全部“待办事项”,包括复合任务与原子任务,比如主厨清单里的“备料”和“洗菜”。
    T={t1, t2, …, tn}T = \{t_1,\ t_2,\ \ldots,\ t_n\}
  2. C(约束集合)约束描述任务之间的关系,比如“先备料再烹饪”“炖汤的同时可以切菜”“甜品与主菜不能同时上桌”。
    C={ ti≺tj, ti∥tj, …}C = \{\,t_i \prec t_j,\ t_i \parallel t_j,\ \ldots\}

世界的说明书:领域与任务

主厨的头脑里装着一本“厨房百科全书”:知道红烧肉需要焯水、糖色要小火炒、炖汤和切菜可以同时进行。这本书记录的不是某一道菜的做法,而是这个厨房里所有可行的工序。HTN把这本百科全书的专业名字叫做“领域描述”(Domain Description)。

领域描述了这个世界里“能做什么、怎么做”。它主要由三类知识构成:任务、方法与条件。任务是“要做什么”,不关心做法;方法是“可以怎么做”,是一张预定义的分解模板;条件则是“在什么情况下才允许用这个方法”。数学上,一个方法可以表示为一个四元组:待分解的任务、前提条件、以及分解出的子任务列表。

领域描述的厚薄决定了NPC的“厨艺上限”。方法越丰富,NPC面对新局面就越从容;反之,方法库里空空如也,再聪明的规划器也巧妇难为无米之炊。在设计HTN时,最花心思的往往不是算法本身,而是这本“百科全书”写得够不够详尽、够不够贴合游戏世界的规则。

m=( t, pre, st1, st2, …, stk )\displaystyle m = (\,t,\ pre,\ st_1,\ st_2,\ \ldots,\ st_k\,)
方法就是菜谱里的“一页纸”:写明了做这道菜之前需要备齐什么(前提),以及按什么顺序操作(子任务)。
  1. t(待分解任务)这个方法是用来分解哪一个复合任务的。主厨看到“红烧肉”,就知道该翻到哪一页菜谱。
    t=cook_red_braised_porkt = \text{cook\_red\_braised\_pork}
  2. pre(前提条件)调用方法前的环境检查,相当于“食材、炊具是否齐备”。条件不满足就不能用这个方法,必须换一页菜谱。
    pre=(has_pork∧has_soy_sauce)pre = (\text{has\_pork} \wedge \text{has\_soy\_sauce})
  3. st₁……stₖ(子任务列表)分解后的具体步骤,通常是原子任务或更小的复合任务。它是有序编排的工序,前后关系由领域作者预先设计。
    {st1, st2, …, stk}={wash, chop, braise, reduce}\{st_1,\ st_2,\ \ldots,\ st_k\} = \{\text{wash},\ \text{chop},\ \text{braise},\ \text{reduce}\}

规划算法流程

主厨定好总目标后,不会一口气把所有菜都排成流水线菜单,而是一边拆解一边检查:高汤底还有没有?烤箱温到了吗?如果某个条件不满足,他会换一个方法、修改局部安排,再继续往下拆。这就像在迷宫里走一步探一步,走不通就退回岔路口换条路。

HTN规划器同样如此。它维护一个待分解的任务列表,不断循环两个步骤:匹配方法与递归分解。匹配时检查环境状态是否满足方法的前提;分解时把复合任务替换为方法定义的子任务,并把这些子任务重新加入待办列表。当待办列表里所有任务都变成原子任务时,规划成功;如果某条路失败,就回溯换一种方法继续探索。

规划是有代价的——不同的计划在耗时、消耗、风险上各有不同。规划器通常会为每个原子动作设定一个执行成本,再通过搜索找出总成本最低的计划。规划完成后,NPC按计划的顺序执行,同时持续监控环境;一旦发现前提不成立,就可能触发重新规划。

就这样,主厨的每一次“换方法”都会让整张作战地图局部重绘,而规划器通过成本函数评判哪条路更划算。剥到最后,一颗完整的洋葱变成了整齐码放的菜叶——一份可以直接照做的、经过成本优化的行动计划。

Cost(π)=∑i=1ncost(πi)\displaystyle Cost(\pi) = \sum_{i=1}^{n} cost(\pi_i)
规划器不是“找到一条路就完事”,而是希望在众多可行方案里挑出最经济的一条。晚宴主厨也会比较“炖老火汤”和“煲快速汤”哪个更合适。
  1. π(计划)最终产出的一条有序动作序列,对应主厨排出的当日执行清单。
    π=[ a1, a2, …, an ]\pi = [\,a_1,\ a_2,\ \ldots,\ a_n\,]
  2. cost(πᵢ)(单步成本)每个动作的执行代价,比如“慢炖”比“焯水”耗时更长、占用灶台更久。
    cost(braise)=90,cost(wash)=5cost(\text{braise}) = 90,\quad cost(\text{wash}) = 5
  3. Σ(总成本求和)把计划中所有动作的成本加起来,数值越小代表这条计划越经济。规划器在分解过程中会不断比较不同方法产生的候选计划。
    Cost(π)=90+5+30+…Cost(\pi) = 90 + 5 + 30 + \ldots

传统行为树对比

传统行为树像餐厅里那本装订成册的固定菜单。翻开第一页:洗菜;第二页:切菜;第三页:下锅。菜单本身不会变,每天上菜的顺序都按部就班。可晚宴上突然有客人说“我不吃香菜”,按固定菜单操作的服务员和帮厨就愣住了——菜单里没有这一页。

行为树(Behavior Tree)正是这样一套“可预测的反应器”。它用选择器和顺序器组合成一个决策结构,NPC每帧从根节点往下遍历,根据环境条件选择要执行的分支。它速度快、确定性高,但习惯怎么走就怎么走,很难临场规划出一条全新路径。HTN则完全不同:每次接到新目标,它现构思、现分解、现出计划,像主厨临时拿出一张手写菜单。

选型上没有绝对优劣。行为树擅长高频、短周期、结构稳定的决策,比如战斗中的闪避、攻击连招;而HTN擅长一次性的、有明确目标的任务,比如“攻占据点”“护送商队”。许多大厂游戏的做法是“混搭”:外部用HTN规划大方向,进入战斗后切换行为树处理精细动作——既保效率,又保灵活。

可以说,行为树是“流程”,HTN是“规划”。两者不是替代关系,而是不同层级的工具:主厨也会把“颠勺”这种熟练动作交给肌肉记忆(行为树),而把整场宴席的统筹交给大脑(HTN)。理解这一点,你就能在项目里做出更明智的技术选型。

实时重构与优化

晚宴进行到一半,后厨突然发现高汤锅烧干了。一位成熟的主厨不会推倒整场宴席重来,而是悄悄把“老火汤”替换成“速成冬瓜汤”,其余步骤照旧。这就是计划修复——不动全局,只改堵点。

游戏里的世界同样善变:玩家突然炸毁了NPC要走的桥,天气系统改变了巡逻路线。HTN规划器在计划执行中要持续检查“计划是否仍然成立”。如果不成立,有两种应对:完全重规划——丢弃旧计划,从目标重新分解;局部修复——保留仍然有效的部分,只重建失效的子网络。前者彻底但昂贵,后者快速但有风险。

实时性对游戏AI是硬指标。常用的优化手段包括:惰性分解——不到执行前一刻不展开子任务,减少无谓计算;方法缓存——同一状态下重复匹配的结果直接复用;成本启发式——给常用方法以更高优先级,引导搜索快速收敛。用复杂度术语来说,规划的搜索开销正比于分解深度d和每个任务的平均方法数b,即阈值深度下最坏情况是b的d次方量级。

主厨的智慧不只在于会做菜,更在于锅糊了时不慌张。HTN的优秀实现也都带着这种“遇事不决,局部重排”的冷静,配合惰性分解与缓存,让NPC在变化的世界里依旧从容。对玩家来说,这意味着他们看到的不再是卡在墙边反复踱步的傻AI,而是会绕路、会改道的“活人”。

O(b d)\displaystyle O(b^{\,d})
这是HTN规划最坏情况下的搜索开销估算:每个复合任务平均有b种方法可选,要分解d层才能到达原子动作,组合数就会指数增长。精简方法库,就是在为NPC“减负”。
  1. b(分支因子)一个复合任务平均有多少个候选方法。主厨知道“做汤”有五种做法,分支因子就是5。
    b=∣methods(t)∣b = \left| \text{methods}(t) \right|
  2. d(分解深度)从目标到原子动作需要拆几层。晚宴目标可能拆3层才到“洗菜”,分解深度就是3。
    d=depth of decompositiond = \text{depth of decomposition}
  3. O(b^d)(搜索复杂度)最坏情况下规划器要尝试的组合数呈指数增长。所以领域设计要把b和d都压小,好比主厨不会摆出100种“做汤”的方案,而是精选5种最实用的。
    O(bd)=O(53)=O(125)O(b^d) = O(5^3) = O(125)

实战案例与工具

如今,“会临场拟菜单的主厨”已经走进了许多知名餐厅——在游戏AI领域,HTN正成为越来越多工作室的标配。它不是实验室里的纸上谈兵,而是经历过商业项目检验的成熟方案。

几个典型场景:RTS游戏里,AI指挥官收到“占领矿场”的目标,HTN自动分解为“侦察→集结→进攻→驻守”,并在矿场被玩家抢占时改道“转移目标”;开放世界中,村民NPC依据时间、天气、库存动态安排一天的“赶集”计划;而工具链方面,Unity、Unreal生态都出现了成熟的HTN插件,例如Fluid HTN和HTN Planner,让中小团队也能快速上手。

工程师落地HTN的主要工作集中在领域设计——编写任务、方法和条件。它不需要训练数据,也不需要大量调参,但非常考验领域建模能力:方法划得太粗,NPC傻;划得太细,领域文件爆炸。好的团队会像维护菜谱库一样维护方法库,用单元测试验证每种方法的可达性。一些团队还会为领域文件设计可视化编辑器,让策划直接拖拽生成方法模板,进一步降低使用门槛。

回到宴会厅,这位主厨之所以游刃有余,不光因为手快,更因为案台上摆着一套精心整理的“方法卡片”。HTN工程实践的成败,同样藏在那些看似琐碎的领域描述里。掌握了HTN,你就掌握了让NPC“活起来”的那把钥匙。

AI 应用场景

RTS游戏单位的实时调度

阶段:规划与决策

解决的问题:传统脚本只能写死进攻路线,玩家绕后一次就失效,AI部队会傻傻地冲向空无一人的目标点。HTN让AI指挥官从“占领矿场”这一抽象目标出发,动态分解出侦察、集结、进攻、驻守四个子目标,并在战场情报变化时自动重排计划,让部队永远围绕目标行动而非背台词。

具体案例:某RTS游戏中,AI据点被围困,将军单位收到“解围”目标。HTN实时生成“侦查敌情→呼叫援军→两翼夹击”的计划;当侦查发现敌军主力已转移时,规划器局部修复为“正面施压→占据制高点”,成功化解围困。

开放世界NPC的日常行为模拟

阶段:行为生成

解决的问题:为上百个村民手写行为繁琐且僵化,每个NPC都是循环播放的“人形木偶”。HTN让每个NPC根据自身状态(饥饿、困倦、金钱)从“过好今天”的目标出发,动态分解出吃早饭、赶集、砍价、回家休息等任务,让村庄真正“活”起来。

具体案例:早晨,农夫看到天气晴朗,选择方法“晴天户外工作”,把“安排今日工作”分解为“去田地→播种→正午回村吃饭”;如果突然下雨,规划器检测到条件变化,迅速将计划修复为“去酒馆避雨→修补屋顶”。

机器人任务规划的参考借鉴

阶段:任务规划

解决的问题:HTN源自经典AI规划,在机器人领域同样适用。酒店机器人处理“送毛巾到302房”的目标时,HTN可将其分解为“取毛巾→导航→敲门→交付”,一旦走廊因客人行李拥堵,机器人只需局部重排导航子任务,不必从头规划整个服务流程。

具体案例:某酒店服务机器人使用HTN思想设计任务调度:前台在系统中输入“送餐到605房”,机器人自动规划“乘电梯→走廊→敲门→等待确认→返回充电位”,全程无需人工介入。

Python 演示

python58 行
class HTNPlanner:    def __init__(self):        self.methods = {}        self.primitive_ops = {}        self._call_count = 0     def add_method(self, task, pre, subtasks):        self.methods.setdefault(task, []).append({'pre': pre, 'subtasks': subtasks})     def add_primitive(self, name, pre):        self.primitive_ops[name] = pre     def plan(self, task, state, depth=0):        self._call_count += 1        if depth > 6:            return None        if task in self.primitive_ops:            if self._satisfy(self.primitive_ops[task], state):                return [task]            return None        for method in self.methods.get(task, []):            if not self._satisfy(method['pre'], state):                continue            plan = []            ok = True            for sub in method['subtasks']:                sub_plan = self.plan(sub, state, depth + 1)                if sub_plan is None:                    ok = False                    break                plan.extend(sub_plan)            if ok:                return plan        return None     @staticmethod    def _satisfy(pre, state):        return all(state.get(k, False) for k in pre)  def main():    planner = HTNPlanner()    planner.add_primitive('walk_to_market', ['has_legs'])    planner.add_primitive('buy_ingredients', ['has_money'])    planner.add_primitive('walk_home', ['has_legs'])    planner.add_method('go_shopping', ['has_money'],                       ['walk_to_market', 'buy_ingredients', 'walk_home'])    planner.add_method('prepare_dinner', ['has_ingredients'],                       ['go_shopping', 'walk_home'])     state = {'has_legs': True, 'has_money': True, 'has_ingredients': True}    plan = planner.plan('prepare_dinner', state)    print('plan:', plan)    print('planner calls:', planner._call_count)  if __name__ == '__main__':    main()
目的:实现一个可运行的最简HTN规划器,演示复合任务"prepare_dinner"如何通过方法递归分解为原子动作序列。
  1. self.methods.setdefault(task, []).append(...)为每个复合任务维护一个候选方法列表,相当于主厨案头那摞“方法卡片”。
  2. planner.add_primitive('walk_to_market', ['has_legs'])注册原子任务及其前置条件,原子任务不再需要分解。
  3. for method in self.methods.get(task, [])遍历当前复合任务的所有候选方法,就像主厨翻看几种做汤方案。
  4. if not self._satisfy(method['pre'], state): continue前提不满足就跳过该方法,等价于“冰箱里没肉,换一道素菜”。
  5. self.plan(sub, state, depth + 1)递归分解子任务,深度限制防止方法循环引用导致死循环。
  6. plan.extend(sub_plan)把子计划按顺序拼接进总计划,最终得到一串原子动作。

常见误区

误区HTN名字里带“树”,又和行为树一样用于游戏AI,那HTN肯定是行为树的升级版,学了HTN就不用学行为树了。

正解行为树是反应式决策器,每帧按固定结构遍历节点;HTN是规划式决策器,每次从目标出发动态生成计划。它们解决的是不同问题:战斗闪避这类高频动作适合行为树,攻城略地这类一次性目标适合HTN。两者是互补工具,没有高低之分。就像主厨既用肌肉记忆颠勺(行为树),也用大脑统筹宴席(HTN)。

为何常见:名字都带“树”字,且常用领域高度重叠,初学者极易混淆“反应式决策”与“规划式决策”的本质区别。

误区HTN性能很差,因为环境一变就得全部重算,根本没法用在对实时性要求高的游戏里。

正解完全重规划只是策略之一。工程实现常用局部计划修复、惰性分解、方法缓存等优化手段,只在必要时才重算受影响的那一小块子网络。合理设计后,HTN的每帧开销完全可以控制在毫秒级。这就像主厨发现汤锅烧干,只换一道汤,不会把整桌菜都推翻。

为何常见:教材和论文通常只讲“规划失败就回溯重算”的基础算法,忽略了工业级实现里的大量优化技巧。

误区方法里列出的子任务列表就是固定的先后清单,必须从头到尾按顺序做,不能并行也不能跳步。

正解方法只定义“任务如何分解”,真正的执行顺序由任务网络中的约束决定,可以表达顺序、并发、互斥等关系。比如“炖汤”与“切菜”在领域里可以标记为并行任务,主厨在炖汤的同时就能切配菜。子任务列表只是方法的一种呈现形式,不代表唯一时序。

为何常见:大多数教程用列表或数组展示子任务,让人误以为方法内部必然是严格串行。

误区HTN是动态规划的,每次执行结果都不一样,过程完全不确定,出了问题也没法查。

正解HTN的规划过程是完全确定的:给定相同的领域描述、初始状态与目标,规划器每次都会走出相同的分解路径。工程上可以记录每个任务的分解决策、显示候选方法选择树、支持单步跟踪。调试焦点从行为树的“条件分支”变成了HTN的“分解选择”,只是观察角度变了,并非不可调试。

为何常见:动态生成的计划不像行为树那样有固定的可视化结构,缺乏经验的开发者容易误以为它无法观测。

面试题

Q1. HTN中“复合任务”的核心特征是什么?

单选题 · easy

  • A.直接对应一个游戏动作
  • B.需要方法分解为子任务← 正确答案
  • C.只能被动等待外部触发
  • D.不需要考虑任何执行条件

答案:B。复合任务是“还没想好怎么做”的抽象目标,必须通过匹配方法分解为子任务;能直接执行的是原子任务。选项A描述的是原子任务,C和D都偏离了HTN复合任务的本质,因此B正确。

Q2. 下列哪些属于HTN领域描述中的组成元素?

多选题 · mid

  • A.复合任务定义← 正确答案
  • B.方法的前提条件← 正确答案
  • C.原子任务定义← 正确答案
  • D.玩家按键映射

答案:ABC。领域描述由任务(复合+原子)、方法和条件组成。复合任务定义告诉规划器“有哪些目标”;前提条件决定方法何时可用;原子任务定义直接可执行的动作。玩家按键映射属于输入系统,不属于HTN领域知识,故D不选。

Q3. 方法m=(t, pre, subtasks)中,pre的主要作用是什么?

单选题 · mid

  • A.描述任务在领域中的名字
  • B.规定子任务列表的位置
  • C.控制方法何时可被选用← 正确答案
  • D.计算整条计划的执行成本

答案:C。pre是方法的“准入条件”,只有环境状态满足全部前提时,规划器才允许用这个方法分解当前任务,如同主厨做红烧肉前先确认冰箱里有肉。A是t的作用,B是subtasks的作用,D与成本公式无关。

Q4. 关于行为树与HTN,下列说法正确的是?

多选题 · mid

  • A.行为树适合高频稳定决策← 正确答案
  • B.HTN适合一次性规划目标← 正确答案
  • C.两者可以混合搭配使用← 正确答案
  • D.HTN不需要领域知识库

答案:ABC。行为树逐帧遍历、延迟低,适合闪避、连招等高频稳定决策;HTN从目标出发生成计划,适合“占领据点”等一次性规划目标;业内常用HTN定大方向、行为树管细动作。D错误,HTN高度依赖领域描述,没有领域知识库就无法分解任务。

Q5. HTN规划器最终输出的“计划”是什么?

单选题 · easy

  • A.一棵可调试的行为树
  • B.原子动作的有序序列← 正确答案
  • C.一组随机生成的权重
  • D.一张渲染用的贴图资源

答案:B。规划器不断把复合任务分解为子任务,直到任务网络里只剩原子任务,最终得到的是一条有序的原子动作序列,即主厨那张“当日执行清单”。A是行为树的产物,C和D与规划完全无关。

Q6. NPC执行计划途中发现桥梁被炸毁,最合适的应对策略是?

单选题 · mid

  • A.无视计划继续执行原方案
  • B.触发局部计划修复机制← 正确答案
  • C.删除所有已生成的任务
  • D.降低NPC的移动速度值

答案:B。桥梁被毁说明原计划中的“过桥”子任务失效,局部计划修复只需重建过桥这段子网络(如改走浅滩),其余部分照旧。A会导致NPC卡死,C矫枉过正,D与问题无关,故选B。

Q7. 以下哪些手段可以有效降低HTN实时规划开销?

多选题 · hard

  • A.惰性推迟分解时机← 正确答案
  • B.缓存方法匹配结果← 正确答案
  • C.使用成本启发剪枝← 正确答案
  • D.增加前提约束条件

答案:ABC。惰性分解把子任务延后到执行前一刻,减少无效展开;方法缓存复用相同状态下的匹配结果,避免重复计算;成本启发式引导搜索优先尝试低开销方法,缩小探索范围。D增加无谓的前提约束会提高计划失败率,反而不利于实时性。

Q8. 搜索复杂度O(b^d)中,b与d分别代表什么?

单选题 · hard

  • A.树深度与叶子节点数量
  • B.分支因子与任务的分解深度← 正确答案
  • C.计划成本与收益的比值
  • D.动作数量与耗时总和的比值

答案:B。b是分支因子,指一个复合任务平均有多少种候选方法;d是分解深度,指从目标到原子动作需要拆几层。最坏情况下规划器要尝试的组合数就是b^d量级。A是行为树的术语,C和D与复杂度公式无关。

Q9. 下列哪个是Unity生态中的HTN插件?

单选题 · easy

  • A.Fluid HTN插件工具← 正确答案
  • B.NavMesh导航网格
  • C.ProBuilder建模工具
  • D.Shader Graph着色器插件

答案:A。Fluid HTN是Unity生态中知名的HTN插件,提供可视化编辑器让开发者快速搭建领域描述。NavMesh是寻路系统,ProBuilder是关卡建模工具,Shader Graph是着色器编辑器,三者都不属于HTN规划插件。

Q10. 复合任务分解失败后,规划器的标准处理方式是什么?

单选题 · mid

  • A.立即终止NPC所有行为
  • B.回溯尝试其他可用方法← 正确答案
  • C.将失败原因写入日志即可
  • D.随机挑选一个方法继续

答案:B。当前方法的前提不满足或子任务无法分解时,规划器会回溯到复合任务,尝试方法列表中的下一个候选,就像主厨发现红烧肉没法做时改做卤豆腐。A过度反应,C只记日志不解决问题,D随机选择会破坏规划的确定性与质量。