2d自上而下顺利寻路libGDX

问题描述:

我试图让一个跟随玩家(由你控制)周围的玩家和目前它的作品,但是当我添加碰撞检测时,它不工作得很好,当哥们遇到障碍。我只是想知道什么是最好的方法(如可能是a *算法的实现)使ai运动平滑并避免障碍? 这里是我的哥们类目前更新方法:2d自上而下顺利寻路libGDX

public void update() { 

    setBounds(getX(), getY(), getWidth(), getHeight()); 

    float xDiff = Math.abs(player.getX() - getX()); 
    float yDiff = Math.abs(player.getY() - getY()); 

    if (player.getX() > getX() && xDiff > buddyDistance) { 
     setX(getX()+speed); 
    } 
    else if (player.getX() < getX() && xDiff > buddyDistance) { 
     setX(getX()-speed); 
    } 

    if (player.getY() > getY() && yDiff > buddyDistance) { 
     setY(getY()+speed); 
    } 
    else if (player.getY() < getY() && yDiff > buddyDistance) { 
     setY(getY()-speed); 
    } 

} 
+0

运动是否被限制为一个图,比如一个网格?如果是这样,我确实有一个可能的解决方案。但是,如果玩家以任意步长移动,并且您希望该伙伴跟随而不限制其沿着某个图形移动,那么我将不得不进一步思考。 – Eulerson

+0

不,玩家不会被限制在网格中,我不会使用平铺地图或类似的东西 – Moulie415

的解决方案易于实施,可能取决于你的类型的障碍物的工作是利用潜在领域。

这个想法很简单:玩家的行为像一块磁铁,把伙伴拉向他。同时,障碍击退了好友,让好友避开它们。

为了更好的可读性,我将首先使用矢量来解释它,而不是Java。

比方说,b是好友的位置和p玩家和o_1, ... o_k是您的障碍物的位置。

b, p, o_1, ..., o_k的每一个是具有xy坐标的2维向量。

然后向量(p-b)是从好友指向玩家的向量。我们还需要的是从障碍i指向好友的向量(b-o_i)。此外,我们不是直接使用矢量(p-b),(b-o_i),而是先对它们进行归一化处理。

然后,normalized(p-b)已经是我们需要把好友拉给玩家了。

为了排除好友的障碍,我们希望如果好友靠得很近,排斥力就会强,如果好友离得很远,就会使其排斥力小(甚至为零)。因此,一个明显的选择是按比例缩放我们想要的方向,即normalized(b-o_i),其中1/|b-o_i|,其中|。|表示向量的范数。现在

,我们可以简单地混合所有这些“磁力”有:

w = normalized(p-b) + normalized(b-o_1)/|b-o_1| + ... + normalized(b-o_l)/|b-o_k| 

这个载体w通常指向朝球员,但每当哥们接近障碍物就会从他们被排斥,这是正是你想要的。

但我们如何确保伙伴以正确的速度移动? 这很简单。我们将w标准化,然后按速度进行缩放。也就是说,我们的最终速度矢量是v = speed*w/|w|

这可以很容易地添加到您的代码:

public void update() { 

    setBounds(getX(), getY(), getWidth(), getHeight()); //I kept this from your code, but I don't actually know what it does 

    float dx = player.getX() - getX(); //note: I removed abs 
    float dy = player.getY() - getY(); 

    float norm = Math.sqrt(dx*dx + dy*dy); 

    //normalization: 
    float wx = dx/norm; 
    float wy = dy/norm; 

    for (obstacle o : obstacles) { //assuming obstacles is an iterable datastructure containing instances of the class obstacle 
     //note, it suffices to iterate over close by obstacles 
     dx = getX() - o.getX(); 
     dy = getY() - o.getY(); 

     norm = Math.sqrt(dx*dx + dy*dy); 

     //normalization: 
     float ox = dx/norm; 
     float oy = dy/norm; 

     //add scaling to get the repulsion force we want 
     wx += ox/norm; 
     wy += oy/norm; 
    } 

    float norm_of_w = Math.sqrt(wx*wx + wy*wy); 
    float vx = speed * wx/norm_of_w; 
    float vy = speed * wy/norm_of_w; 

    setX(getX() + vx); 
    setY(getY() + vy); 
} 

不幸的是,有几件事情要考虑:

  • 不同种类的排斥可能工作优于1/| b-o_i |,例如1/| b-o_i |^2。
  • 这可能有助于玩弄部队,例如试用c*(b-o_i)/|b-o_i|对于c(即ox = c*dx/norm;等)的不同值。如果c太小,那么好友会在一定程度上进入障碍,如果c非常大,他会在远离它们时已经避开它们。对不同的障碍物尺寸使用不同的c值可能会给出更好的结果。
  • 如果障碍物为圆形并且两个障碍物之间有足够的空间,避开障碍物效果最佳。否则,该伙伴可能会陷入局部最佳状态,玩家将不得不通过移动到将该伙伴拉离本地最佳值的位置来“拯救”他。
  • 如果障碍物不好且是圆形的,但是大的多边形,则可以尝试覆盖大部分多边形的非常大的斥力(即对于这种障碍非常大的c)。好处是,好友可以避开障碍,但不幸的是,如果你想让它靠近它,它会因为强烈的排斥而被拒绝。
  • 请注意,如果伙伴和障碍物接近,1/|b-o_i|就很大。如果他们处于相同的位置,那么你的程序将尝试除以零。你可能想检查这个案例,并避免它。

就是这样,但它可能是值得注意的是,通常与潜在的领域,这个想法是利用负电荷的目标和障碍正电荷,即

w = -|p-b| + 1/|b-o_1| + ... + 1/|b-o_k| 

注意在这里,w只是一个标量而不是一个向量。然后,应用渐变下降向目标移动。这意味着w相对于b.x,b.y的梯度被计算出来。然后这个渐变指向到达玩家的方向,同时避开障碍物。这是比我提出给你更好的方法,但需要更多的数学知识。随意尝试或问这是否是你想要的。


最有可能,最好的答案,如果有障碍,任意形状,局部极小不适合你接受的是使用的三角网与漏斗算法相结合。你可以阅读更多关于是在https://www.aaai.org/Papers/AAAI/2006/AAAI06-148.pdf

但我认为你更喜欢的东西,很容易实现。