A*尋路算法所生成的路徑

本文目的是對A*尋路算法所生成的路徑進行一些人性化的調整,使其看起來不至於太機械化。關於A*算法的原理與實現,讀者可以閱讀其他資料,這裏不再詳細闡述。

如何寫估價函數

        A*尋路算法本質上是一個有方向性的廣度優先搜索算法,它使用一個估價函數,來估測可能的最短路徑,在每一次搜索迭代完成後,選取其鄰接點中最優的一個(即,距離終點最近的一個點),作爲下一次迭代的起點。如此反覆,直到找到終點。下面先列出估價函數的常規寫法:


        設i點到起點的價值爲S,到終點的估價爲E,i點的總估價G等於S+E。S的值是確定的:


[cpp] view plain copy 在CODE上查看代碼片派生到我的代碼片

  1. S = parent.S + 1(i點是其父節點的水平或垂直方向上的鄰接點)  

  2. 或  

  3. S = parent.S + sqrt(2))(i點是其父節點斜方向上的鄰接點)  


E點的值需要估算。精確一點的寫法:


[cpp] view plain copy 在CODE上查看代碼片派生到我的代碼片

  1. 水平距離:dx = abs(ix - ex)  

  2. 垂直距離:dy = abs(iy - ey)  

  3. 需要斜着走過的距離:v1 = min(dx, dy) * sqrt(2)  

  4. 需要直線走過的距離:v2 = max(dx, dy) - min(dx, dy)  

  5. E =  v1 + v2  


粗略的寫法:


[cpp] view plain copy 在CODE上查看代碼片派生到我的代碼片

  1. E = abs(ix - ex) + abs(iy - ey)  


如何避免轉向抖動

        A*尋路得到的結果是最優的,但不是唯一的,這源於兩點之間最近的路線可能不只一條。那麼問題就產生了,兩條最佳路線距離都相等的情況下,哪一條會更好?

    

(紅色是障礙,白色可通行,黑色是搜索路徑)

        如上圖所示,是A* 8方向搜索得到的兩條距離相等的路線,但是左圖的路線在中間位置發生了“拐彎”,要比右圖的路線多一個“拐彎”。如果路線上拐彎太多,人物行走的過程中,會出現頻繁轉向,從而出現“抖動”現象。所以,我們判定右圖路線優於左圖路線。針對這一問題,我們可以通過修改估價函數,來選擇“拐彎”更少的路線。

        拐彎的問題,可以簡化成先儘可能的向一個方向走,然後再考慮轉向。進一步簡化成,點越接近起點或是終點,越優先考慮。我們給E加上一個干擾值factor,


[cpp] view plain copy 在CODE上查看代碼片派生到我的代碼片

  1. factor = min(abs(ix - sx), abs(ix - ex)) + min(abs(iy - sy), abs(iy - ey))  

  2. factor *= 0.01  


factor的值不能過大,否則會造成搜索結果不是最短距離,因此適當的給factor乘上一個縮放係數。

如何遠離障礙物

        A*尋路的效果是抄近道,走捷徑。但對於遊戲體驗來說,這並不完全是件好事,放着寬闊的馬路不走,非得走懸崖峭壁,一不小心就跌落萬丈深淵,或者卡在岩石邊上。那麼,我們該如何避免這些現象呢?同樣,我們可以通過修改估計函數做到。

        我們給每一塊可走區域都加上一個干擾值,越靠近障礙的可走區域,其干擾值越大。干擾值計算方法:


[cpp] view plain copy 在CODE上查看代碼片派生到我的代碼片

  1. factor = 0  

  2. for(x = -n; x <= n; ++x)  

  3. {  

  4.       for(y = -n; y <= n; ++y)  

  5.      {  

  6.         if(isObstacle(ix + x, iy + y))  

  7.         {  

  8.             factor += n - min(abs(x), abs(y))  

  9.         }  

  10.      }  

  11. }  


        我們甚至可以根據地表的材質來增加干擾值,比如山路和沼澤地帶明顯比馬路的干擾值大。

後記

        總之,我們可以調節估價函數來達到不同的效果。但是,也不能隨意修改,不良的估價函數,會增加搜索成本。


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