zoukankan      html  css  js  c++  java
  • AI逻辑实现-取舍行为树还是状态机

    AI逻辑实现-选择行为树还是状态机? 
    关注AI的朋友可能会看过赖勇浩翻译的《有限状态机时代终结的10大理由》 ,里面谈到了状态机的诸多弊端。同时在ppt(附上下载地址)中述说了行为树的诸多优点,这里就不在赘述了。更多得是想总结一下自己玩了一阵子行为树后的一些实践体会。

    个人体会: 
    状态机来实现AI更符合我们思维的朴素表达,我想任何一个有经验的coder都能直观得去写一个自己的AI状态机。它用于一些简单的ai其实是没有大问题的,(搜索敌人,靠近,攻击,死亡)用状态机其实更加便捷。但是面对一些复杂的ai逻辑实现就会显得比较繁杂。同时,当需要对现有行为逻辑进行扩展的时候,代码上就会显得比较吃力,因为要维护的状态量会成倍增加。 
    这里写图片描述 
    行为树,实现AI的过程更加得有技巧,框架设计者较为全面考虑了我们可能会遇到的种种情况,把每种情况都抽象成了一个类型的节点,而我们要做的就是按照规范去写节点,然后把节点连接成一颗行为树。更加得具有面向对象的味道,行为模块间的藕合度相对较低。

    举个粗糙的例子来比较一下两者的不同: 
    AI行为:吃饭 睡觉 打豆豆(很消耗体力和脑力的;)

    1.打豆豆 HP -= 5 / 秒 MP -= 3 / 秒 
    2.吃饭 HP += 10/秒 MP -= 1 / 秒 
    3.睡觉 MP += 15/秒 HP -= 2/秒 
    4.吃饭和睡觉是不可打断的动作(pending),必须执行到吃饱(HP = 100) or 睡饱(MP = 100) 
    5.打豆豆是瞬发动作,每帧都可以执行一次

    状态机的实现逻辑图: 
    这里写图片描述 
    行为树的实现逻辑图: 
    这里写图片描述 
    其实不管你知不知道什么是selector,condition都不要紧,至少从上图,应该可以看出来,行为树节点间的联系并不像状态机那样得“紧密”。

    选择两种不同的ai实现方法,也决定了具体行为的实现逻辑。 
    比如对于sleep动作的实现,如果是状态机: 
    function sleep() = 
    if Y == 100 then 
    AwakeEvent() 
    return 
    end 
    HP -= X 
    MP += Y 
    end 
    然后每一帧执行sleep()

    如果是选择行为树: 
    function sleep() 
    local sleepTime = (100/15) 
    –不好意思乱入了一段cocos2dx的代码 
    self:runAction(cc.Sequence:create(cc.DelayTime:create(sleepTime),cc.CallFunc:create(cancelPending))) 
    local cancelPending = function() 
    pending = false 
    end 
    end

    罗列一下行为树的概念: 
    对于有限状态机而言,必须明确 状态的转换方式;对于行为树,必须明确状态前提:前提条件 
    每一个行为必须有“前提条件” ,这决定了该行为是否被选择。 
    行为树的运算也是通过帧循环的update来驱动,不一定是每帧都update,但是要周期性update。 
    每一次run从根节点(root)开始,每一运行都会选择一个可行的子节点运行,这种选择可以是随机方式,也可以是预设好优先条件 
    行为树由叶子节点和中间节点组成,叶子节点是最基本的行为(如跑动,攻击),中间节点代表逻辑单元(巡逻,逃跑)。 
    当一个叶子节点被选择后,就会激活其对应的基本的行为 
    最基本的行为可能执行成功也可能失败。 
    高等级的行为(中间节点)是否执行成功依赖于他们的孩子节点是否执行成功。 
    一个子节点失败可能导致父母节点选择另外一个孩子。 
    除了选择(selector)一个单独的子节点行为,一个节点还可能顺序(sequence)or并行(concurrent)得运行他的所有子节点。 
    一个行为除了有前提条件,可能还有上下文条件(父节点or孩子节点可能存储一定的状态变量)。 
    高优先级的行为可能抢占低优先级的行为

    转载一段akara的行为树实现方案:

    • Composite Node 组合节点
    • Decorator Node 装饰节点
    • Condition Node 条件节点
    • Action Node 行为节点

    各种节点的详细描述: 
    * Selector Node 选择节点 
    描述:从头到尾,按顺序选择第一个执行条件为真的子节点,遇到True停止。 
    处理流程:当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:如遇到一个Child Node执行后返回True,那停止迭代,本Node向自己的Parent Node也返回True;否则所有Child Node都返回False,那本Node向自己的Parent Node返回False。

    • Sequence Node 序列节点 
      描述:从头到尾,按顺序执行每一个子节点,遇到False停止。 
      处理流程:当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:如遇到一个Child Node执行后返回False,那停止迭代,本Node向自己的Parent Node也返回False;否则所有Child Node都返回True,那本Node向自己的Parent Node返回True。

    • Parallel Node 并行节点 
      描述:从头到尾,平行执行它的所有子节点。 
      Parallel Selector Node: 有一个子节点True返回True,否则返回False。 
      Parallel Sequence Node: 有一个子节点False返回False,否则返回True。 
      Parallel Fall On All Node: 所有子节点False才返回False,否则返回True。 
      Parallel Succeed On All Node: 所有子节点True才返回True,否则返回False。 
      Parallel Hybird Node: 指定数量的子节点返回True或False后,才决定结果。

    • Decorator Node 装饰节点 
      描述:装饰节点一般用来作为额外的附加条件。例如,时间间隔控制,次数控制,频率控制,结果取反,错误处理等。

    • Condition Node 条件节点 
      描述:顾名思义,就是对应条件的节点。

    • Action Node 行为节点 
      描述:顾名思义,就是用于完成某种动作的节点。

    从代码实现的角度来谈下优缺点

    优点: 
    1. 行为逻辑和状态数据分离,任何节点写好以后可以反复利用 
    2. 重用性高,可用通过重组不同的节点来实现不同的行为树 
    3. 呈线性的方式扩展,易于扩展 
    4. 可配置,把工作交给designer 
    5. 能够胜任”AI” “掉宝”等等场景。

    缺点: 
    1. 每一帧都从root开始,有可能会访问到所以的节点,相对State Machine消耗更多的cpu 
    2. 任何一个简单的操作都必须要使用节点

    原文地址:http://blog.csdn.net/u011484013/article/details/52369313

  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/AaronBlogs/p/7039816.html
Copyright © 2011-2022 走看看