行为树 Behavior Tree 原理

行为树 Behavior Tree 原理

行为树 树形结构图如下一棵倒置的树
行为树 Behavior Tree 原理_第1张图片

行为树采用节点描述行为逻辑,主要有:选择节点、顺序节点、并行节点、修饰节点、随机节点、条件节点、行为节点。一棵行为树表示一个AI逻辑。要执行这个 AI 逻辑,需要从根节点开始遍历整棵树,遍历执行的过程中,父节点根据自身的类型,确定需要如何执行、执行哪些子节点并继续执行,子节点执行完毕后,会将执行结果反馈给父节点。

从结构上节点可分为:组合节点、叶节点 (单节点)。组合节点就是拥有子节点的节点。叶节点 (单节点)就是没有子节点的节点。

组合节点:选择节点、顺序节点、并行节点、修饰节点、随机节点。
叶节点 :条件节点、行为节点。

如下图一个行为树示例图:

行为树节点顺序如下,
节点1 为根节点, 节点2、节点5为中间节点,节点3、4、6、7,为子节点
节点 1、2、5为组合节点,节点3、4、6、7为单节点
行为树 Behavior Tree 原理_第2张图片

节点执行结果
条件执行结果可分为三种:Fail、Success、Running
Fail : 节点执行失败(如:条件节点判定为 false、执行节点失败、没有符合执行的节点等)
Success:节点执行成功(如:条件节点判定为 true、执行节点成功等)
Running:节点执行中(如:正在跑向目标、正在吃饭、动画播放中等)

行为树节点
叶节点

  1. 条件节点
    条件节点(Condition)即是条件判定,例如:“是否饿了?”、“是否有饭?”、“是否有作业”等。
    如果条件测试结果为真,向父节点返回 Success,否则返回 Fail。
    条件节点一般作为叶节点。
  2. 行为节点
    行为节点(Action)用来执行实际的工作,如:做饭、吃饭、打球、写作业等。行为节点有些可能一帧就可以执行完成,有些可能需要多帧才能完成。行为节点执行过程中失败,向父节点返回 Fail,执行完毕向父节点返回 Success,正在执行中时向父节点返回 Running。

组合节点
组合节点用来控制树的遍历方式,每种组合节点的遍历方式都不相同。
1.选择节点
选择节点(Select),遍历方式为从左到右依次执行所有子节点,只要节点返回 Fail,就继续执行后续节点,直到一个节点返回Success或Running为止,停止执行后续节点。如果有一个节点返回Success或Running则向父节点返回Success或Running。否则向父节点返回 Fail。

注意:当子节点返回 Running时,除了停止实行后续节点、向父节点返回 Running 外,还要保存返回Running 的这个节点,下次迭代则直接从该节点开始执行。
如果选择节点有记录正在 Running的节点,则遍历时就要从上次记录的Running节点开始,而不是从最左边第一个节点开始执行。其他逻辑不变
选择节点伪代码如下:

    index = 1
    if != lastRunningNode null then
        index = lastRunningNode.index
    end

    lastRunningNode = null
    for i <- index to N do 
    
        Node node =  GetNode(i);

        result = node.execute()
        
        if result == fail then
           continue;
        end

        if result == success then
            return success
        end

        if result == running then
            lastRunningNode = node
            return running
        end

    end

return fail

2.顺序节点
顺序节点(Sequence),它从左向右依次执行所有节点,只要节点返回Success,就继续执行后续节点,当一个节点返回Fail或 Running 时,停止执行后续节点。向父节点返回 Fail 或 Running,只有当所有节点都返回 Success 时,才向父节点返回 Success。
与选择节点相似,当节点返回Running 时,顺序节点除了终止后续节点的执行,还要记录返回 Running的这个节点,下次迭代会直接从该节点开始执行。
顺序节点伪代码如下:

    index = 1
    if != lastRunningNode null then
        index = lastRunningNode.index
    end

    lastRunningNode = null
    for i <- index to N do 
    
        Node node =  GetNode(i);

        result = node.execute()
        
        if result == fail then
           return fail;
        end

        if result == running then
            lastRunningNode = node
            return running
        end

    end

    return success

3.随机选择节点
随机节点(Random)遍历优先级与选择节点、顺序节点不同。
选择节点、顺序节点都是默认优先级的,最左边的节点具有最高优先级,最右边的优先级最低。随机节点则是随机执行每个子节点。如从左到右顺序为:A、B、C、D。而执行时可能是D、A、C、B 或 C、B、D、A 等。
当一个节点返回 Success 或者 Running 时,则停止执行后续节点,向父节点返回 Success或Running。当返回 Running 时记录返回 Running 的节点,下次迭代时首先执行 Running 节点。比如做饭时,根据AI心情不同每天随机选择吃 宫保鸡丁、香菇肉片、还是鱼香肉丝。这样提高游戏结果的多样性。

随机节点伪代码:

    Random 一个随机数组

    index = 1
    if != lastRunningNode null then
        index = lastRunningNode.index

        将 index 添加到随机数组的第一位
    end

    lastRunningNode = null
    for i <- 1 to N do 
    
        Node node =  GetNode(i);

        result = node.execute()
        
        if result == fail then
           continue;
        end

        if result == success then
             return result
        end

        if result == running then
            lastRunningNode = node
            return running
        end

    end

    return fail

4.修饰节点
修饰节点(Decorator)修饰节点不能独立存在,其作用为对子节点进行修饰,以得到我们所希望的结果.
修饰节点有很多种,其中有一些是用于决定是否允许子节点运行的,也叫过滤器,例如 Until Success, Until Fail 等,首先确定需要的结果,循环执行子节点,直到节点返回的结果和需要的结果相同时向父节点返回需要的结果,否则返回 Running。
如需要结果为 Until Fail,则当子节点返回 Success或者 Running 时都向父节点返回 Running,当节点返回结果为 Fail 时,才向父节点返回 Fail。
反之需要的结果为 Until Success,则当子节点返回 Fail 或者 Running 时向父节点返回 Running,当节点返回 Success 时,才向父节点返回 Success。

修饰节点常用的几个类型如下:
Inverter 对子节点执行结果取反
Repeater 重复执行子节点 N 次
Return Failure 执行到此节点时返回失败
Return Success 执行到此节点时返回成功
Unitl Failure 直到失败,一直执行子节点
Until Success 直到成功,一直执行子节点

修饰节点 Until Success、Until Fail 伪代码:

     defaultResult = 期望结果

     do
     Node node = GetChild(0)
     result = node.Execute();
    
     if result != defaultResult then
         return running
     end

     return defaultResult
     end

5.并行节点
并行节点(Parallel)有 N 个节点,每次执行所有节点,直到一个节点返回 Fail 或者全部返回 Success为止,此时并行节点向父节点返回 Fail 或者 Success,并终止执行其他所有节点。否则至少有一个节点处于 Running 状态,则执行完所有节点向父节点返回 Running。与选择节点不同的是并行节点不需要记录返回 Running 结果的节点,每次执行都会从左向右依次执行所有子节点。
当外界环境发生变化时,影响到子节点的执行,如何处理?如,AI 正在炒菜,突然煤气不足,无法点燃,则AI 就不能继续炒菜这个动作了,将退出炒菜的所有节点。
并行节点对于外部环境发生变化,需要随时应对变化的AI 决策十分有效。如,AI 追逐玩家,使用并行节点就特别合适,需要并行的执行 “是否看到玩家?”,“朝玩家移动”。当某一帧无法看到玩家,则不能执行朝向玩家移动这个节点的行为。
并行节点伪代码:

    successCount = 0

    for i <- index to N do 
    
        Node node =  GetNode(i);

        result = node.execute()
        
        if result == fail then
           return fail;
        end

        if result == success then
            ++successCount
            continue
        end

        if result == running then
            continue
        end
    end

    if successCount >= childCount then
        return success
    end

    return running

到此 行为树 Behavior Tree 中七个常用节点介绍完毕

你可能感兴趣的:(BehaviorTree)