阅读笔记-游戏开发中的人工智能-第5章-以势函数实现移动

1. 概述

    势函数属于物理学原理,我们主要使用势函数控制游戏里单位的行为。例如,我们可以使用势函数,建立成群结队的单位,仿真群体移动,处理追逐和闪躲,以及避开障碍物问题。我们专门研究的势函数叫做Lenard-Jones势函数。

    
    物理学中,Lenard-Jones势能代表的是,分子间吸引和排斥的势能。这里的U代表的是原子内的势能,和分子的间隔距离r成反比。A和B是参数,与m和n这两个指数一样。如果我们取该势函数的导数(derivative),就可得到一个代表某力的函数。这个力函数根据这两个分子的接近程度,产生引力和斥力,就我们的情况而言,分子指的就是游戏中正在行动的单位。就是这种可以表示引力和斥力的能力,能让我们受益。通过调节参数,可以转化引力与斥力,这样就可以实现追逐和闪避了。除了追逐和闪避之外,使用斥力进行障碍物躲避,使用引力形成群体等。
      
                                                            图-势函数图像    
 2. 追逐和闪避
     有两架飞机,Craft1和Craft2,Craft1由玩家控制,Craft2由计算机控制。通过计算Craft2与Craft1的势能,得到Craft2的力,从而控制Craft2的移动方式。 

void DoAttractCraft2(void) {
    Vector r 
= Craft2.vPosition - Craft1.vPosition;
    Vector u 
= r;
    u.Normalize();
    
double U, A, B, n, m, d;
    A 
= 2000// 引力强度
    B = 4000// 斥力强度
    n = 2// 引力衰减
    m = 3// 斥力衰减
    d = r.Magnitude() / Craft2.fLength; // 考虑到尺度伸缩的目的
    U = -A/pow(d, n) + B/pow(d, m); // 这里实际上求出的是势能,后面就把这个势能当做力的大小了    

    Craft2.Fa 
= VRotate2D(-Craft2.fOrientation, U * u); // U*u给力一个方向,然后通过旋转坐标轴后,在把该力加到单位上
    Craft2.Pa.x = 0// 最后这几句没看懂
    Craft2.Pa.y = Craft2.fLength / 2;
    Target 
= Craft1.vPosition;
}

    通过调整参数,会产生某些结果,如下图:

    
                                               图-势能的追逐和闪避

    ·(A)中,追击者朝猎物前进,当猎物和他擦身而过时,他会绕回来。当追击者太接近时,会突然转一下,以维持两单位间的某些分隔距离,感觉像是跑的太快跑过了,又回头追。
    ·(B)中,我们减少引力分量的强度(把A的值减少一点),其结果就很像拦截,感觉像是跑的刚刚好,撞到了。
    ·(C)中,我们增强引力的强度,结果很像基本视线算法。增强到多少呢,比A中的还大?这个不得而知了就。
    ·(D)中,我们减少引力,增加斥力,并调整指数参数,结果计算机控制的单位就会逃离玩家。

3. 避开障碍物

    基本思路就是:把A参数设为0,只留下斥力分量,通过调整参数B,决定斥力强度,以及指数m,决定衰减程度。
    举例来说,地图上有很多障碍物,计算机控制一个单位在地图上移动并且能够避开障碍物。在计算斥力的时候,需要把所有的单位对该单位产生的斥力都考虑进去,综合的结果,就是对该单位实际作用力。
    下面就是一个势能避开障碍物的程序运行效果:
     
                                                         图-势函数避开障碍物

4. 成群结队

    使用势能函数实现群体行为,不需要基本群聚的规则,只需要计算任意两个单位之间的势能,从而得到每个单位身上的力就够了。
    代码忽略了,下面是群体的图像:
   
                                                             图-成群结队

    (A)是这些单位聚在一起的图形。(B)是每个单位所走的路径。显然,路径会缠绕交叉在一起。这样的结果很像是蜜蜂或苍蝇的集体行为。
    另外,如果让群体能够追猎物,躲避障碍物,那么就把追击和躲避产生的势能与群体势能加在一起就好了,当然,实现不同目的的势能函数的参数是不同的。
    此外,如果指定某个特定单位作为领头者,然后令其吸引其他单位,那么当领头者移动时,这个成群结队的群体,倾向于自我组织,比较优雅的群居行为。

5. 关于最佳化的建议

    使用势能的群聚算法的复杂度是N*N的。下面尝试通过优化,减小复杂度。
    对于障碍物避开算法,对于相距较远的障碍物,可以不去计算势能。因为距离较远的话,无论引力或者斥力都很小,影响也小。设定一个范围阈值就好了。这样虽然对于所有的障碍物都要判断是否在阈值内,也就是说仍旧是N,但是计算势能的复杂度就小了很多很多。
    如果想要判断的复杂度减低到N一下,可以把游戏领域分成网络,每一个格子都配置一个数组,来存储落在这个格子里面的障碍物数据。当计算某个单位的势能时,我们只需要处理与该单位同在一个格子里面的单位以及这个格子周围的一圈格子中的单位。这样就下降到了N以下了。
    对于群聚的算法,使用格子,可以是N*N的复杂度,降低到N的常数倍,这样可以大大节约CPU时间。而且对于i,j之间的势能,只需要计算一次就够了。
   

posted @ 2011-05-20 10:20  xiaodongrush  阅读(1168)  评论(0编辑  收藏  举报