1. 程式人生 > >cocos creator主程入門教程(十)—— A*尋路

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

.com 行為樹 中間節點 取出 span 深度優先 如果 inf lose

摘要: 五邑隱俠,本名關健昌,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*尋路算法先說到這裏,下一篇我們將介紹行為樹。

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