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

时间: 2024-12-05 09:38:34

AI逻辑实现-取舍行为树还是状态机的相关文章

AI逻辑实现-选择行为树还是状态机?

关注AI的朋友可能会看过赖勇浩翻译的<有限状态机时代终结的10大理由> ,里面谈到了状态机的诸多弊端.同时在ppt(附上下载地址)中述说了行为树的诸多优点,这里就不在赘述了.更多得是想总结一下自己玩了一阵子行为树后的一些实践体会. 个人体会: 状态机来实现AI更符合我们思维的朴素表达,我想任何一个有经验的coder都能直观得去写一个自己的AI状态机.它用于一些简单的ai其实是没有大问题的,(搜索敌人,靠近,攻击,死亡)用状态机其实更加便捷.但是面对一些复杂的ai逻辑实现就会显得比较繁杂.同时,

MMORPG大型游戏设计与开发(服务器 AI 逻辑设定和状态结点)

人工智能(AI)中往往都会有这么一个问题,那就是我要做什么?我该怎么做?我需要什么?所以这里所谓的智能就是赋予AI对象的判断力,以及它根据判断得到的相应反应.就好比,你去商店买东西,钱够别人才卖给你,不够不可能卖你,这里就会触发了两种结果,如果你要强买的话,那么店员就可能产生相应的措施了.其实这里的店员,就相当于我们所谓的人工智能,不过店员的反应和动作是根据他自身思考产生的,人工智能也有这个思考的过程,只不过比店员想的少很多.这个思考的过程,也就是逻辑设定与处理的过程,那么什么又是状态结点呢?

游戏设计模式——黑板模式

"黑板"(Blackboard)在人工智能领域已经是一个很古老的东西了.它基于一种很直观的概念,就是一群人为了解决一个问题,在黑板前聚集, 每个人都可以发表自己的意见,然后在黑板上写下自己的看法,当然你也可以基于别人记录在黑板上的看法, 来发表和更新自己的看法,在这样不断的意见交换,看法更新的过程中,越来越趋向于对于问题的最终解答. 一开始的黑板模式就是这样一个由多个子系统来共同协作的人工智能解决方案. 定义 基于上面的描述,我们可以看到黑板有几个功能: 记录:每个人可以写下自己的看法

状态机和行为树

最近在思考游戏AI,看到一些文章在鼓吹状态机(fsm)已经过时,行为树才是现在和将来.目前我的水平,对这个结论无法做评判.但是从读到的文章本身,没有看到有力的证据. 诚然,在复杂状态下,fsm的维护难度是倍增的,但行为树也面临同样问题(不要看那些半吊子文章中画的清晰的属性结构,真的复杂场景哪里有这么好看的树).fsm的分层能缓解一部分复杂度问题,我相信行为树也是通过类似子树的方式处理,所以就是个半斤八两. 另外,看到说行为树的判别因子有{前置条件 , 当前状态, 输入},较之fsm的{当前状态,

AI行为树关键字分析

Decotator(装饰)既然作为条件判定分为了三种判定类型, 第一:控制输入的类型,比如BlackBoard 第二:控制输出的类型,比如Force Success 第三:控制执行方式,比如Loop 系统中自定义了很多常用的Decotator,IsAtLocation(判断是不是在某个坐标) ForceSuccess(强制输出成功) CampareBBEntris(比较两个黑板Key) Loop(循环,可以设置次数) ConditionLoop(达成条件在进行循环)(条件通过KeyQuery设定

游戏AI(二)—行为树优化之

上一篇我们讲到了AI架构之一的行为树,本篇文章和下一篇文章我们将对行为树进行优化,在本篇文章中我们讲到的是内存优化 问题 上一篇中我们设计的行为树由于直接采用new进行动态内存分配,没有自己进行管理.因此行为树各节点的存储位置会散布在内存空间的各处,行为树在不同节点中切换时会导致Cache频繁失效. 通过内存管理改变行为树节点的内存分布,可以显著提高行为树的内存性能. 解决办法 我们可以在BehaviorTree中引入一组内存分配的API来保证各节点尽量分配在连续的内存上,代码如下 Behavi

行为树的理解和学习

最近打算好好研究一下行为树,在使用行为树之前,我们应该先理解行为树的基本概念和相关的逻辑,然后我们就Unity3D平台下的行为树插件的使用来进行学习行为树. 什么是行为树 如果了解过状态机,会知道在行为树之前,在实现AI用得比较多的技术是状态机,状态机理解起来是比较简单的,即一个状态过渡到另一个状态,通过判断将角色的状态改变即可,如果学习过Unity的Mecanim动画系统,会更加直观的理解. 但是状态机在状态较多的情况下会使状态之间的切换变得异常繁琐,同时状态之间很难复用. 在这种情况下,行为

解密游戏团队AI

很多人问游戏AI该怎么做?随着游戏类型的多元化,非 MMO或者卡牌的游戏越来越多,对AI的需求也越来越强了.而市面上关于 AI的书,网上找得到的文章,也都流于一些只言片语的认识,理论化的套路,和一些简单的 DEMO,离真正的项目差距甚远,无法前后衔接成一条线,更无法真正落地到编码. 国内真正做过游戏AI的少之又少,东拉西扯的人很多,真正做过项目的人很少,因为国内主要以MMO为主,RTS比较少,体育竞技类游戏更少,而从AI的难度上来看,应该是:MMO < FPS < RTS < 体育竞技.

Unity中的行为树插件:Behavior Designer

外国技术人员的插件:http://www.opsive.com/assets/BehaviorDesigner 目前公司内部比较推崇的行为树插件就是这个,虽然有其他几个同类的竞品. 说一句题外话,优秀的插件总是外国人开发的,并且可以将插件开发做成一个小工作室或者个人的主要收入来源,但没看到国人有类似的作品出现. 行为树的概念出现已经很多年了,总的来说,就是使用各种经典的控制节点+行为节点进行组合,从而实现复杂的AI.目前在游戏中一般复杂的AI都可以看到行为树的身影,简单的AI可以使用状态机来实现