[英]2d top down smooth pathfinding libGDX
我正在嘗試制作一個跟隨玩家(由您控制)的伙伴AI,此刻它可以正常工作,但是當我添加碰撞檢測時,當伙伴撞到障礙物時效果不佳。 我只是想知道什么是使ai運動平穩並避免障礙的最佳方法(例如a *算法的實現)? 這是我的好友類當前的更新方法:
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
坐標的二維向量。
那么向量(pb)
是從伙伴指向玩家的向量。 我們還需要從障礙物i
指向伙伴的向量(b-o_i)
。 此外,我們首先將它們標准化,而不是直接使用向量(pb)
和(b-o_i)
。
然后, normalized(pb)
已經是我們將好友拉到播放器所需的全部。
為了使好友遠離障礙,我們希望如果好友靠近它,排斥力要強,如果好友遠離它,排斥力應該很小(甚至為零)。 因此,一個明顯的選擇是縮放所需的方向,即使用1/|b-o_i|
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相對於bx,by的梯度。 然后,該坡度指向避開障礙物同時到達玩家的方向。 這是比我向您建議的方法更好的方法,但是需要更多的數學知識。 隨意嘗試或詢問這是否是您想要的。
最有可能的是,如果障礙物具有任意形狀且局部最小值對您不可接受,則最佳答案是將Delaunay三角剖分與漏斗算法結合使用。 您可以在https://www.aaai.org/Papers/AAAI/2006/AAAI06-148.pdf中了解更多信息
但是我認為您喜歡易於實施的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.