用簡單直白的方式講解A星尋路演算法原理

2022-05-19 02:14:19 字數 2173 閱讀 9012

很多遊戲特別是rts,rpg類遊戲,都需要用到尋路。尋路演算法有深度優先搜尋(dfs),廣度優先搜尋(bfs),a星演算法等,而a星演算法是一種具備啟發性策略的演算法,效率是幾種演算法中最高的,因此也成為遊戲中最常用的尋路演算法。

直入正題:

在遊戲設計中,地圖可以劃分為若干大小相同的方塊區域(方格),這些方格就是尋路的基本單元。

在確定了尋路的開始點,結束點的情況下,假定每個方塊都有乙個f值,該值代表了在當前路線下選擇走該方塊的代價。

而a星尋路的思路很簡單:從開始點,每走一步都選擇代價最小的格仔走,直到達到結束點。

a星演算法核心公式就是f值的計算:

f = g + h

f - 方塊的總移動代價

g - 開始點到當前方塊的移動代價

h - 當前方塊到結束點的預估移動代價

以下詳細解釋這個公式,方便更好地理解它。

g值是怎麼計算的?

假設現在我們在某一格仔,鄰近有8個格仔可走,當我們往上、下、左、右這4個格仔走時,移動代價為10;當往左上、左下、右上、右下這4個格仔走時,移動代價為14;即走斜線的移動代價為走直線的1.4倍。

這就是g值最基本的計算方式,適用於大多數2.5drpg頁遊。

基本公式:

g = 移動代價

根據遊戲需要,g值的計算可以進行拓展。如加上地形因素對尋路的影響。格仔地形不同,那麼選擇通過不同地形格仔,移動代價肯定不同。同一段路,平地地形和丘陵地形,雖然都可以走,但平地地形顯然更易走。

我們可以給不同地形賦予不同代價因子,來體現出g值的差異。如給平地地形設定代價因子為1,丘陵地形為2,在移動代價相同情況下,平地地形的g值更低,演算法就會傾向選擇g值更小的平地地形。

拓展公式:

g = 移動代價 * 代價因子

h值是如何預估出來的?

很顯然,在只知道當前點,結束點,不知道這兩者的路徑情況下,我們無法精確地確定h值大小,所以只能進行預估。

有多種方式可以預估h值,如曼哈頓距離、歐式距離、對角線估價,最常用最簡單的方法就是使用曼哈頓距離進行預估:

h = 當前方塊到結束點的水平距離 + 當前方塊到結束點的垂直距離

題外話:a星演算法之所以被認為是具有啟發策略的演算法,在於其可通過預估h值,降低走彎路的可能性,更容易找到一條更短的路徑。其他不具有啟發策略的演算法,沒有做預估處理,只是窮舉出所有可通行路徑,然後從中挑選一條最短的路徑。這也是a星演算法效率更高的原因。

每個方塊的g值、h值是怎麼確定的呢?

g值 = 父節點的g值 + 父節點到當前點的移動代價

h值 = 當前點到結束點的曼哈頓距離

最後,a星演算法還需要用到兩個列表:

開放列表- 用於記錄所有可考慮選擇的格仔

封閉列表- 用於記錄所有不再考慮的格仔

以上就是要完成a星演算法所需要的東西,而演算法的過程並不複雜。

a星演算法偽碼:

a、將開始點記錄為當前點p

b、將當前點p放入封閉列表

c、搜尋點p所有鄰近點,假如某鄰近點既沒有在開放列表或封閉列表裡面,則計算出該鄰近點的f值,並設父節點為p,然後將其放入開放列表

d、判斷開放列表是否已經空了,如果沒有說明在達到結束點前已經找完了所有可能的路徑點,尋路失敗,演算法結束;否則繼續。

e、從開放列表拿出乙個f值最小的點,作為尋路路徑的下一步。

f、判斷該點是否為結束點,如果是,則尋路成功,演算法結束;否則繼續。

g、將該點設為當前點p,跳回步驟c。

後續優化

以上就是a星演算法最基本的原理,明白了基本原理,用2,3百行**寫出乙個可用的a星演算法並不難。當然a星演算法在實際應用中不僅於此,還可以對細節進行優化:

1、選擇排序更快的二叉樹來作為開放列表,幫助我們更快地從開放列表中取出f值最小的點;

2、對何種情況下可以走斜線路徑加以判斷;

3、採用布蘭森漢姆演算法預先判斷兩點是否可以直接通行,可通行就直接返回兩點的直線路徑,不可直接通行再採用a星演算法尋路,提高尋路效率;

4、a星演算法得出尋路路徑後,可採用弗洛伊德演算法對路徑進行平滑處理,使人物走動更為自然

這裡只是用語言講解a星演算法原理,並沒有配圖講解整個尋路的過程,希望進一步直觀理解整個過程的,推薦參考下面兩個網友翻譯過來的a星教程

用最簡單的方式理解正則3

我們繼續前面的內容 示例3 強調內容 需求 匹配出qwe裡不同也是可以的 import re citing re.match a za z w a za z qwehl group print citing 輸出 qwehl 內容所以我們來試試加 的方法 import re citing re.ma...

用最簡單的方式解釋依賴注入

在軟體工程領域,依賴注入 dependency injection 是用於實現控制反轉 inversion of control 的最常見的方式之一 控制反轉用於解耦 class c j jpublic c j j this.j j 本質也是第三方依賴注入,但是這個第三方可以脫離類。將物件依賴對映資...

用最簡單的方式固定表頭 固定首列

主要思想就是用多個table拼湊成乙個table造成固定的假象,話不多說直接上 以下 主要是控制 樣式 以下 是重點啦,乙個 只有thead,另乙個 只有tbody 123 456 下面是建立tbody的tr和td,可忽略不看 實現效果圖如下 如果你想簡單實現固定表頭,以上 已經可以做到啦,但是以上...