我试着做一个跟随玩家(被你控制)的巴迪艾,但是当我添加碰撞检测时,当伙伴碰到一个障碍时,它就不能很好地工作。我只是想知道怎样才是最好的方法(比如a*算法的实现)来使ai运动平滑,从而避免障碍?下面是当前用于我的好友类的更新方法:
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);
}
}
发布于 2017-08-31 23:55:48
一个易于实现并可能根据您的障碍类型而工作的解决方案是使用潜在字段。
这个想法很简单:玩家的行为就像一块磁铁,把同伴拉向他。同时,障碍击退了伙伴,从而避免了障碍。
我将首先使用向量来解释它,而不是Java,以获得更好的可读性。
比方说,b
是好友的位置,p
是玩家的位置,o_1, ... o_k
是障碍的位置。
每个b, p, o_1, ..., o_k
都是具有x
和y
坐标的二维矢量。
然后向量(p-b)
是从伙伴指向播放器的向量。我们还需要向量(b-o_i)
,它从障碍物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);
}
不幸的是,有几件事需要考虑:
c*(b-o_i)/|b-o_i|
的不同值的c
(即ox = c*dx/norm;
等)。如果c
太小,那么伙伴会在一定程度上移动到障碍物中,如果c
非常大,他就会在离他们很远的时候避开它们。对于不同的障碍物尺寸,使用不同的c值也可以得到较好的效果。1/|b-o_i|
是很大的。如果它们处于相同的位置,那么您的程序将尝试将其除以零。您可能想检查一下这个情况,并避免它。就是这样,但也许值得注意的是,通常对于潜在的领域,想法是用负电荷来实现目标,而对障碍使用正电荷,即
w = -|p-b| + 1/|b-o_1| + ... + 1/|b-o_k|
注意,在这里,w只是标量,而不是向量。然后,采用梯度下降来实现目标。这意味着w相对于b.x,b.y的梯度被计算出来。然后,这个梯度指向到达球员的方向,同时避免障碍。这是一个比我建议的更好的方法,但需要更多的数学知识。可以自由地尝试或者询问这是否是你想要的。
最有可能的,最好的答案,如果障碍有任意形状和局部极小是不可接受的,你可以使用Delaunay三角剖分结合漏斗算法。您可以在https://www.aaai.org/Papers/AAAI/2006/AAAI06-148.pdf中阅读更多关于is的信息。
但我想您更喜欢易于实现的东西。
https://stackoverflow.com/questions/45916071
复制相似问题