在整个F.E.A.R的这个游戏中,游戏开发者只使用了有3个状态的有限状态机,不过通过Astar算法进行动作规划,AI能呈现出复杂的动作,如找掩体,遮挡火力线,穿越窗户,用闪光弹震撼玩家等一系列看起来非常智能的行为。
给大家推荐一个交流+学习 705182843
这个有限状态机的三个状态是:去往,执行动作,与灵活物体交互。
在F.E.A.R这款游戏中,大部分的与灵活物体交互都是直接由动画数据来驱动的,所以我们也可以更加简化的把整个游戏中的有限状态机改成两种状态。去往和执行动作。所以到最后整个AI的核心内容其实就是通过参数控制这两个状态的转换,控制AI的行走的目的地和需要播放什么动作而已。状态机的转换就变成了关于动画执行逻辑的一些内容了,比如是否这个动作要循环播放或者只播放一次。
最终我们将这些动画执行的逻辑和AI的规划系统对应了起来。这个规划系统告知AI什么时候要从当前动画状态转移出去,或者进入另外一个动画状态中。总体而言,这个规划系统最终完成了掩体系统,小队交流,及战术策略这三个大的要求。
我们可以看到的是,在当今的3A游戏开发中,AI会变得越来越复杂,而设计这些复杂AI也会变成一项庞大复杂的工作,我们用于F.E.A.R这款游戏中的算法就能很好的解决这个问题。
FSM有限状态机 VS 规划
我们现在就来对比一下有限状态机和我们的规划算法的区别吧。有限状态机是告诉AI在每个特定的情况下应该如何行动。而我们的规划算法只需要目标是什么和我们能怎么行动就可以了,其会自动的规划出一条完整的动作序列能完成我们给与的目标。总体而言,状态机是偏向于公式化的,而规划算法是指导性的,两者结合起来才能最好的完成我们整体的AI设计。在继续往后推进之前,我希望明确一个概念,规划的本质是一个搜索算法,搜索特定的行动序列,来满足我们提出的目标。
STRIPS Planning的简述
我们使用的是STRIPS规划算法。目标是以我们想达成的状态组合来描述的,而每个动作则是由前置条件和效果来组成的。然后我们需要使用和行为相关的向量来描述我们的状态。比如我们坐在家中喝着饮料这个状态可以这么表示<坐,喝> = <家,饮料>我们只要确定我们的目标状态,就有对应的动作可以供我们选择。
然后我们通过一个例子来解释。
小A现在饿了。饱这种状态可以有两种行为达到。
小A可以订外卖的方式获得晚餐,不过他要有订餐电话。
小A可以自己做一顿饭,不过他要有配料。
那么达到饱的这个状态。电脑会给我们规划处两条可选的路径出来,而可选道路的最终选择又是基于小A当前的状态。
这就是最简单的STRIPS规划算法的一个例子。在这个例子中我们还没有加入规划的选择性,不过我们自己来看的话,订外卖会比自己做饭要容易得多。
我们也可以从上述的这个例子中看到,一个动作是需要前置和效果的。比如订外卖,前置就是,有订餐电话这个状态。而后置就是进入饱这个状态。那么一个动作就可以这么来描述
动作就是带外卖小子的这个图片所描述的内容。需要注意的是,我们在状态上的更改,不能使用bool来表示我们是否是饱,而是需要在执行动作后再表中加入我们的新状态,在执行动作前删掉描述我们的现在状态的信息。否则,比如在订餐的过程中。如果单单使用bool类型来表示我们的饥饿与否的状态的话,那就是从饥饿往不饥饿的状态中,这种似是而非的难以解释的状态。
回到刚刚的例子,加入我们有一个新人,比如说小B,他也饿了,但不过他有朋友,那么我们针对小B,就可以加入一个可以选择和朋友一起出去吃饭的选项。小B如果套用小A的AI话,他仅仅是需要新增加一个动作而已。
上述的例子就解释了我们在F.E.A.R中如何设计AI.我们要AI做的事情,仅仅是消灭威胁,为了达到没有威胁这个状态。AI会选择所有可以达到没有威胁这个状态的动作。比如在一定距离的前提下,使用枪械射击威胁(也就是我们的玩家)或者在近距离的情况下,用近战攻击的方式击杀我们的玩家。
具体的例子
在F.E.A.R中,我们需要加入一个AI,然后给他一堆可选的行动,然后一个我们希望AI达到的指定状态(一般而言是杀死玩家)就可以了。我们的编辑器需要维护每个动作的前提和效果就可以了,多个AI之间可以复用编辑器已经设定好的动作。比如下图
老鼠(Rat)他的行为就只有动作,发呆,走到某个点和使用灵活物体。而其他的AI,可使用的动作就多多了。
如果用一个图来表示我们游戏运行中的效果的话。就是下图
我们只是把状态放到了一个开阔的图中,而不是像标准状态机一样写一大堆的状态转移。