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);
}
}
的解决方案易于实施,可能取决于你的类型的障碍物的工作是利用潜在领域。
这个想法很简单:玩家的行为像一块磁铁,把伙伴拉向他。同时,障碍击退了好友,让好友避开它们。
为了更好的可读性,我将首先使用矢量来解释它,而不是Java。
比方说,b
是好友的位置和p
玩家和o_1, ... o_k
是您的障碍物的位置。
b, p, o_1, ..., o_k
的每一个是具有x
和y
坐标的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
但我认为你更喜欢的东西,很容易实现。
运动是否被限制为一个图,比如一个网格?如果是这样,我确实有一个可能的解决方案。但是,如果玩家以任意步长移动,并且您希望该伙伴跟随而不限制其沿着某个图形移动,那么我将不得不进一步思考。 – Eulerson
不,玩家不会被限制在网格中,我不会使用平铺地图或类似的东西 – Moulie415