簡體   English   中英

2d自上而下平滑尋路libGDX

[英]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中的每一個都是具有xy坐標的二維向量。

那么向量(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);
}

不幸的是,有幾件事情要考慮:

  • 不同種類的排斥可能比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相對於bx,by的梯度。 然后,該坡度指向避開障礙物同時到達玩家的方向。 這是比我向您建議的方法更好的方法,但是需要更多的數學知識。 隨意嘗試或詢問這是否是您想要的。


最有可能的是,如果障礙物具有任意形狀且局部最小值對您不可接受,則最佳答案是將Delaunay三角剖分與漏斗算法結合使用。 您可以在https://www.aaai.org/Papers/AAAI/2006/AAAI06-148.pdf中了解更多信息

但是我認為您喜歡易於實施的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM