— AI分享站

Archive
Tag "goap"

前段时间,谈到了一种层次化的AI架构,通过“请求”来隔离出“决策层”和“行为层”,这种架构的核心是通过“请求”来起到承上启下的作用,并由此得出当前AI所应当有的行为,所以可以称之为“请求导向(Request-Oriented)”的结构。这种结构比较适用于需要频繁做AI决策的游戏场合,比如体育类游戏等,一旦变换了请求之后,行为层就可以迅速的找到相应的行为来完成请求的内容。

这次我们换一种思路,来讨论一种“目标导向(Goal-Oriented)”的AI结构,这种结构对于一些持续性相对较长的AI策略来说,是非常适用的。还是先举个例子吧,我平时很喜欢玩星际(没玩过的同学,可以看我下面的描述),那假设我用单个农民(SCV)造一个人族的重工厂(Factory),造重工厂的前提是需要200水晶(Mineral)资源,100气体(Gas)资源,而且必须要先造好兵营(Barrack),兵营是150水晶资源,还有在采集气体资源前,需要造一个气矿(Refinery),气矿也需要100水晶资源,具体流程图如下:

GoalOrientedExample

在这个流程里,我们为这个农民设定的“目标”就是“造一个重工厂”,由于在游戏中,要完成这个目标前,需要有其他一系列的预备行为,如果我们为这个农民写AI的话,它就需要根据上面的流程一步步的来完成我们要求它的“造一个重工厂”的目标。由于所有的AI行为决策都是由指定的目标引起的,所以我们把它称之为“目标导向(Goal-Oriented)”的AI架构。

由上面的例子我们可以看到,一个目标之后,必然会有一系列的行为与之对应,而这些行为就是为了最终完成这个目标,那这些行为是如何串联的呢?或者说,我们如何来做这样的行为计划呢?在“目标导向(Goal-Oriented)”的AI架构中,一般都会存在一个称之为“计划器(Planner)”的模块,由这个模块负责生成这样的行为序列,计划器有两种工作方式,一种是静态的,一种是动态的。

静态的计划器是在游戏设计时,对于所有已定义的可用目标,预先设计好计划流程,就像我们上面这个例子,我们就对“造一个重工厂”这个目标预先设计了一套计划流程,当游戏中的农民收到这个目标后,就会按照我们定义的这个流程来做。

动态的计划器是在游戏运行时,实时的根据目标来计划行为,因为我们看到,计划中每一个单步的行为都存在“前提(Precondition)”和“效果(Effect)”两个部分,“前提”就是做这个行为需要满足的条件,“效果”就是这个行为对于游戏世界的影响。还是用上面这个例子,像“造兵营”这个行为,它的前提就是“需要有150水晶资源”,它的效果就是“当前存在一个兵营”,再如“造重工厂”,它的前提就是“需要200水晶资源”,“需要100气体资源”,“当前存在一个兵营”,它的效果就是“当前存在一个重工厂”,可以看到,前一个行为的效果会成为了下一个行为的前提,所以有了这样的定义,我们就可以通过一些算法,来把可用的行为串联起来,形成一个计划,这样最后一个行为的效果,就是我们所定义的目标。

除了核心的计划器模块,我们还需要目标选择(Goal Selector)模块,来选择我们当前要完成的目标(相当于更高层的决策层),还有一个就是计划实施(Plan Stepper)模块(相当于行为层),用来按部就班的完成计划中各个行为,这两个模块比较好理解,就不多说了,有了上面几个部分的定义,我就可以画出这样的“目标导向(Goal-Oriented)”的AI架构图:

GoalOrientedArchitecture

由上图可以看到这种架构也是相当清晰的,核心的计划器部分在具体实现的时候,还有各种各样值得讨论的地方,本文作为抛砖引玉的作用就不多提了,以后可以继续讨论。现在的游戏AI中,这种Goal-Planner架构的也占了相当大的比例,在动态的计划器的驱动下,可以呈现出多样和逼真的AI行为,希望这篇文章对大家了解这种架构起到一些帮助。

————————————————————————
作者:Finney
Blog:AI分享站(http://www.aisharing.com/)
Email:finneytang@gmail.com
本文欢迎转载和引用,请保留本说明并注明出处
————————————————————————

Read More

AI结构中,有一种情况非常容易出现,就是程序员会非常希望有一块区域,大家可以读取,存储一些信息,并且这块区域是全局共享的。不管是写作看似丑陋的全局变量,还是有一定组织的Blackboard结构,或者作为参数一路传到底,这种结构可以被统称为共享数据(Share Data)。作用就是在不同的模块间传递变量。

共享数据的需求,从某种程度上说,源自程序员的一种”偷懒“(当然这里没有任何贬义),试想一下,一块可以非常方便,存我想存的,读我想读的结构,一块非常松散且容易理解的结构,一块非常容易架构(或者几乎不用架构)的结构,相信很多人都会作为第一选择吧。确实,共享数据的优势很大,很有吸引力,在开发中,可以作为很多问题的解决方案,几乎在所有的引擎中,都或多或少存在着一些共享数据的模块。

在网上的很多文章里,探讨了多种共享数据的结构,OO开发,使得这种结构多了更多的灵活性,不再是以前一个structure走天下了,比如前面说到黑板系统,这个可以说是现在AI中经常会用到的结构,在FEAR的GOAP里就用到了Blackboard,用作在Planner间作数据共享(以后可以写篇文章介绍一下GOAP,我非常喜欢的一个AI架构)。但不管这么样,共享数据的本质还是相同的。

共享数据是一种优点和缺点同样明显结构,下面我们来看看它的缺点

首先,就是共享数据很容易乱,这是伴随它的随意性而生的,共享数据的内容会随着开发进程不停的被修改,或添加新的变量(这种情况居多),或删除冗余的变量(由于开发过程是多人协作的,所以,非常有可能的一种情况就是存在两个作用完全相同的变量,只是因为是不同的人加的),如果没有好的维护和清理,共享数据就会逐渐变成”垃圾堆“ -- 随便说一句,这也是我对共享数据的昵称

其次,共享数据会比较难debug,因为修改和读取都是匿名的,也就是说,谁也不知道,谁会在什么时候修改什么变量!这会导致变量被莫名修改,当然,加数据断点,或者好的统一入口,会使情况有所改善。

还有,共享数据很容易造成程序员对他的依赖,会认为任何变量都可以存在其中,而忽视了对本身模块的架构,在某些情况下,它会成为解决问题的最后一棵稻草,问题是,共享数据可以是,但不能每次都是!

sharingdata-1

像我写的标题,”黄金屋“还是”垃圾堆“,不取决于共享数据本身,而是取决于,我们如何去实现,如何去维护,如何去规范,如何去使用。想到这个问题,也源自我最近一段时间的实践和体会,作为一个新的系列的开始吧,下一篇,写点我对架构共享数据模块的想法。

————————————————————————
作者:Finney
Blog:AI分享站(http://www.aisharing.com/)
Email:finneytang@gmail.com
本文欢迎转载和引用,请保留本说明并注明出处
————————————————————————

Read More