cocos creator主程入門教程(十)—— A*尋路

摘要: 五邑隱俠,本名關健昌,10年遊戲生涯,現隱居五邑。本系列文章以TypeScript爲介紹語言。

 

這一篇介紹A*尋路算法。在RPG、SLG、模擬經營類遊戲,有需要給角色尋路的需求,一般尋路我們採用A*尋路算法,A*尋路算法是一種廣度優先啓發性算法。

先說說什麼叫廣度優先。搜索分爲廣度優先和深度優先,主要體現在對節點的展開上。深度優先一直往一個方向查找,如果沒辦法查找下去,在當前節點改變方向繼續查找,直到找到終點。如果無法繼續查找,就回退上一格重複操作。廣度優先把當前節點放入待探索列表,循環從待探索列表裏取出節點進行展開,直到找到終點。如果待探索列表爲空,說明沒有路可走。

啓發性指算法在待探索列表裏取節點時,先預測哪個節點的路徑可能會最短,優先對該節點展開,A*算法基於對未探索路徑的假設和預測,假設所有路都能通行前提下總路徑最短值。在圖論裏,介紹過有一種尋找最短路徑的算法叫Dijkstra算法,該算法基於貪心算法,即當前選擇探索的節點,爲尚未確定最短路徑,當前源點能到達且路徑最短的節點。Dijkstra算法基於已知距離源點最短。爲了便於理解這兩種算法的區別,先介紹下Dijkstra算法。

 

Dijkstra算法知道所有可能的節點,如下圖,知道總共有ABCDE5個節點,尋找從A點出發到各點的最短路徑。

1)算法有兩個數組,一個維護當前已知最終最短路徑的節點數組S,找到爲路徑字符串和長度,否則爲空字符串,初始只有起點A點標記爲“A”。另一個數組V,維護各個節點“目前所知”從源點出發最短的路徑長度(不一定是最終的最短路徑,初始B標記爲6,D爲7),已經找到最終最短路徑的標記爲0(初始時起點A標記爲0),目前無法到達的標記爲無窮大。

2)循環從數組V中獲取標記非0,非無窮大,路徑最短的節點,在數組S中標記爲1,修正V中其他節點的最短路徑。直到數組S中所有節點都標記爲1

如上圖,尋路的過程爲:

 V:(A,0),(B:6),(C:無窮大),(D:7),(E:無窮大),S:(A,“A”),(B:“”),(C:“”),(D:“”),(E:“”)

 V:(A,0),(B:0),(C:11),(D:7),(E:18),S:(A,“A”),(B:“AB”),(C:“”),(D:“”),(E:“”)

 V:(A,0),(B:0),(C:10),(D:0),(E:18),S:(A,“A”),(B:“AB”),(C:“”),(D:“AD”),(E:“”)

 V:(A,0),(B:0),(C:0),(D:0),(E:18),S:(A,“A”),(B:“AB”),(C:“ADC”),(D:“AD”),(E:“”)

 V:(A,0),(B:0),(C:0),(D:0),(E:0),S:(A,“A”),(B:“AB”),(C:“ADC”),(D:“AD”),(E:“ABE”)

這裏,Dijkstra算法基於知道所有可能的節點,目標節點也有多個,每個節點可以直接到達的節點數沒有限制。

 

遊戲裏的尋路是目標節點只有一個,中間節點可能有多個,每個節點可以直接到達的節點數最多4個(如果是8個方向是8)

將數組改成列表會更靈活,現在將數組V改成open隊列,將數組S改成close隊列。如上圖,要找到A到E的路徑,仍然按照Dijkstra算法思路,

1)先將A放入open隊列,路徑長度爲0

2)循環從open列表裏拿出路徑長度最短的節點,將其放入close隊列並記錄上一節點,對其4個方向進行展開,如果已經在open、close隊列,修正其最短路徑長度;如果不可走,忽略;否則放入open隊列並計算其路徑長度。

3)如果找到E點,通過E點的上一節點,上一節點的上一節點...一直反推到A點,形成反推路徑,從而找到A到E的最短路徑。

4)如果還沒找到E點,open 隊列爲空,A到E路不通。

如上圖,從Dijkstra算法修改過來的尋路算法,按照紅色、綠色、藍色、黃色節點,逐步展開尋找才找到A到E的最短路徑,很多沒用的分支,效率低。

A*的優化思路主要在挑選節點展開時,假設找到一箇中間節點B後,中間節點B到E的路都是可走的。這時候最短路徑長度是計算經過B點A到E的最短路徑(AB)+(BE)。在RPG遊戲中,最簡單的情況是,A到B的路徑長度等於從A走到B經過的格子數,B到E的路徑長度等於假設B到E的路都相通情況下B走到E經過的格子數。A*算法每次展開節點時都儘可能的往可能最短的路徑去展開尋找,減少沒必要的分支,提高尋路效率。

 

下面是A*尋路算法過程

1)先將A放入open隊列,記錄其上一節點爲空

2)循環從open列表裏拿出節點N,N爲經過該點N,A到E路徑預測長度最短的節點,將其放入close隊列;對其4個方向進行展開,如果已經在open、close隊列,修正其上一節點;如果不可走,忽略;否則放入open隊列並記錄其上一節點爲N。

3)如果找到E點,通過E點的上一節點,上一節點的上一節點...一直反推到A點,形成反推路徑,從而找到A到E的最短路徑。

4)如果還沒找到E點,open 隊列爲空,A到E路不通。

 

A*尋路算法先說到這裏,下一篇我們將介紹行爲樹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章