1. 程式人生 > >一種非常簡單有效的基於格子的尋路演算法

一種非常簡單有效的基於格子的尋路演算法

這是之前手遊專案中琢磨出來的一個簡單易行, 同時感覺比較高效的一個尋路演算法.  當然有一個前提, 是基於格子的尋路, 你的格子可以是正方形, 六邊形等. 總之, 從一個格子移動到旁邊任何一個格子的代價是相等的, 也就是步數都是一, 這個演算法可能也適應於其它場景, 當然我對尋路演算法也沒什麼研究, 僅僅是解決了我所遇到的問題.

這是一個最短路徑尋路演算法.

地圖如下, 6 * 6,  當時專案中實際的地圖尺寸為5 * 14, 沒有關係. 原理是一樣的. 

假設我們要從1.2(x = 1, y = 2)移動到5.4, 圖中的紅色部分.


如果地圖上沒有任何障礙, 那麼其中一條(有多條)最短路徑可能是 1.2-->2.2-->3.3-->4.4-->5.4, 一共是4步. 演算法的實現步聚如下:

1. 開放列表(存放等待掃描其周圍的格子) .

將1.2加入到開放列表. 掃描它的周圍, 理論上, 如果你是四邊形的格子, 那麼任何一個格子的周圍都有8個格子(不考慮邊界), 掃描完後, 記下這8個格子到1.2這個座標的距離, 都是一步, 所以下面這個圖中標記的全是1, 這是第一輪掃描.


2. 將1.2從開放列表中移除(它已經掃描過了), 並將剛才掃描的8個格子加入到開放列表.

3. 掃描這8個格子的周圍, 將它們周圍未掃描過(已掃描過的不要參與)的格子標記距離為2, 這是第二輪掃描, 結果如下.


4. 依次類推, 掃描完剩餘的格子, 這裡的規律是, 第一輪掃描的格子的距離離出發點一定是1, 第二輪掃描的離出發點一定是2.  第三輪一定是3. 直到掃完所有的格子, 最終的結果如下:


5. 好了, 如何得到最短路徑呢? 

關閉列表(被選擇到最終路徑中的格子).

我們將5.4加入到關閉列表. 並掃描它周圍每一個格子所標記的步數(從起點1.2過來的步數),  會得到六個格子, 有兩個格子(5.3, 5.5)到1.2有四步, 另外有三個格子到1.2只有三步, 換句話說, 在這裡我們至少有3條最短的路可以回到1.2, 選擇任何一條都可以, 如下圖.


6. 隨便(如果你想角色移動的比較合符自然規律的話, 不能隨便選)選一個, 我們就選4.4, 也就是5.4正左邊的這個格子, 將它加入到關閉列表, 然後再掃描4.4周圍的格子, 同樣找出到1.2需要最少步數的格子, 這裡有兩個(3.4, 3.3), 如下圖.


7. 還是隨便選一個, 3.3, 繼續掃描,  得到2.2和3.3兩個距離1.2的步數都為1的格子, 如下:


8. 再隨便選一個2.2, 再往下掃, 就能碰到1.2了, 接著就不用再掃了, 這個時候, 關閉列表中已經存在一條最短路徑了. 是: 5.4-->4.4->>3.3-->2.2-->1.2

9. 有人要問, 為什麼是從終點5.4向起點1.2反向掃描呢? ^:^

10. 有障礙的情況下, 如何處理? 如下圖中, 4.1, 4.2,4.3, 4.4, 4.5都無法通過.


 其實還是按照之前的掃描方式就可以了, 只是當碰到障礙時不用標記, 最終掃描的結果如下, 一樣可以得到最短路徑.


11. 優化, 這個演算法存在一些優化的可能, 例如.

a). 如果1.2至5.4方向的前一排, 即2.0 ~ 2.5全部無障礙時, 我們就可不必掃描1.2身後所有格子, 因為這時不必繞路. 如果1.2在地圖中間, 那將有一半的格子不用參與計算.

b). 某些條件下是否可以掃描到5.4之時, 對身後的格子不再掃描? 這樣, 如果5.4在地圖中間, 那麼也將有一半的格子不用參與計算.

 請尋路演算法高手不吝賜教, 另外, 上面有幾張圖有個小錯誤: 0.5這個格子應該標註為(3), 而不是(2).