再譯《A *路徑搜索入門》之流暢版??

A *路徑搜索入門php

帕特里克·萊斯特發表於2003年10月8日下午8點33人工智能html

若是您發現文中有錯誤或問題(丟失的影像或文件,受損代碼,不正確的文本格式等),致使沒法閱讀它時,請聯繫編輯,以便能更正。感謝您幫助咱們改善這個資源。程序員

更新於2005年7月18日算法

這篇文章已被翻譯成阿爾巴尼亞語,中文,法語,德語,葡萄牙語,俄語和西班牙語。歡迎其餘的翻譯。在這篇文章的末尾有聯繫的電子郵件地址。數組

對於初學者, A *(讀A-星,譯者注:老外讀A-star)算法可能有些複雜。雖然在網上有不少解釋A *算法的文章,大多數寫給有基礎的。這篇是給純新手的。(譯者記:各位新手若是有看不懂的,對不起是翻譯的錯。)安全

本文並不試圖成爲這個主題的權威著做。相反,是闡述原理並準備讓你能去閱讀全部其餘的材料及明白他們在說什麼。在本文的末尾提供一些較好,能進一步閱讀的資料的連接。數據結構

最後,這篇文章不是具體的方案。你應該可以接受在文中出現的任何計算機語言。就如同你所指望的那樣,無論怎樣, 在本文的末尾,有一個演示程序的連接。演示包中有兩個版本:一個是C++,一個是Blitz Basic(http://www.blitzbasic.com/Home/_index_.php)。若是想運行A *的程序,也有可執行文件的。app

但是咱們正在超越本身。從頭開始吧...編輯器

■簡介:搜索區域佈局

假設要想從A點到達B點。中間有一堵牆把AB兩點隔開。如面所示,用綠色表示起點A,用紅色表示終點B,並用藍色表示中間的那堵牆。

[圖1]

首先,把搜索區域分割成由方格組成的網格。這叫簡化搜索區域,是路徑搜索的第一步。這種方法把搜索區域簡化成一個二維數組。數組中的每個元素表明了網格里的一個方格,方格被記錄爲能走和不能走。從A點到B點所通過的方格叫路徑。一旦路徑被找到,就能夠從一個方格的中心移到下一個的中心,直到到達目標。

這些中心點被稱爲「節點」。在看別的路徑搜索資料時,常常會看到討論節點。爲何不叫它們方格呢?由於真的有可能不把路徑搜索區域分割成方格。能夠是矩形,六邊形,三角形或任何形狀。節點能夠用任何形狀表示- 在中心或者沿着邊緣,或其餘任何地方。不過,由於方格是最簡單的,咱們使用方格。

 

■開始搜索

一旦把搜索區域簡化成可管理數量的節點,就像上面所說的網格佈局,下一步就是進行搜索來找到最短路徑。從A點開始,檢查相鄰的方格並向外普及搜索,直到找到目標。

執行如下操做開始搜索:

1.從起點A開始,並將它添加到 「開啓列表」。開啓列表有點像一張購物單。儘管如今列表裏只有一個項目,但之後會多起來。它包含了多是你想要的,也可能不是。基本上,這是須要被檢查的方格的列表。

2.尋找起點相鄰的全部可到達或能走的方格,忽略有牆,水或其餘非法的地形。把它們添加到開啓列表。對於每一個方格,保存A點做爲它們的「父」。當要追溯路徑時,父是很重要的。稍後會解釋它。

3.從開啓列表刪除起點A,並將它添加到不須要再次查找的「關閉列表」。

在這一點上,你應該有相似下面插圖的印象。在該圖中,位於中心的深綠色方格就是開始方格。它是輪廓爲淺藍色,以指示它已被添加到關閉列表。對在開啓列表的全部與它相鄰的方格進行檢查,而且用淺綠色來框記它們。每一個方格都有一個灰色的指針指回它們的父,也就是開始方格。

[圖2]

下一步,咱們選擇了開啓列表上的一個相鄰方格,並或多或少地重複前面的過程,以下所述。可是,咱們選擇哪方格呢?一個具備最小F值的。

 

■路徑評分

在算出的路徑時,下面的公式是肯定要使用的方格的關鍵:

F = G + H

這裏

G =從起點A沿着生成的路徑移動到一個給定方格上的運行成本。

H =從給定方格移動到終點B的估計運行成本。這一般稱爲啓發式,這可能有點混亂。由於是一個估測的因此這樣稱呼。在找到路徑以前,咱們真的不知道實際的距離,由於各類各樣的事情都在途中(牆,水等)。在本教程中給出一個計算H的方法,但在網上的其餘文章裏能找到許多計算H方法。

經過反覆遍歷開啓列表,選擇具備最小F值的方格來生成咱們的路徑。在本文中這個過程將有進一步更詳細的說明。首先來仔細看看如何用公式計算。

如上所述,G是從起始點移動到給定點所生成路徑的運動成本。在這個例子中,咱們將指定每一個水平或垂直移動方格成本爲10,對角線移動的成本爲14。咱們使用這些數字是由於沿斜邊移動是2的平方根(不要懼怕),是水平或垂直移動的大約1.414倍。咱們使用10和14是爲了簡單起見。比例大體是正確的,又能避免計算平方根和小數。這不僅是由於咱們是愚笨的,不喜歡數學。採用這些數字是讓計算更快,太快了。你很快就會發現,若是你不使用這些捷徑,路徑搜索可能會很緩慢的。

因爲咱們計算的G值是沿特定的路徑到給定的方格,這個辦法是找出那個方格的父的G值,而後加10或14取決於它從父的移動是正交(非對角線)仍是對角線。在這個例子中這個方法的須要將進一步變得明顯一點,由於咱們從開始方格開始獲得一個以上的方格。

H能夠用各類方式估計。在這裏使用曼哈頓方法,計算從當前方格到目標方格水平和垂直方向移動方格的總數,忽略對角運動,忽略用這種方式可能的任何障礙。而後,將總數乘以10,水平或垂直移動一格的成本。這是(可能)被稱爲曼哈頓方法,由於它像計算城市街區的數量從一個地方到另外一個地方,並不能沿對角穿過。

閱讀本說明,您可能已經猜到了啓發式僅僅是當前方格與目標之間的剩餘距離的一個「像烏鴉飛似的」(譯者注:直線距離)粗略的估計。不是這樣的。咱們實際上試圖估計沿路徑的剩餘距離(一般是更遠)。估計越是接近實際剩餘距離,就是越快的算法。若是高估了這個距離,那麼,它不能保證給初的最短路徑。在這樣的狀況下,咱們有所謂的「不可接受啓發式」。

從技術上講,在這個例子中,曼哈頓方法是不可接受的,由於它稍稍高估了剩下的距離。可是咱們會用也無妨,由於它是一個更容易理解咱們意圖的,由於它只是一個輕微的高估。在極少的狀況下,獲得的路徑不是最短的,這將是逼近最短。想了解更多?你能夠在這裏(http://www.policyalmanac.org/games/heuristics.htm)找到關於啓發式相同的或附加說明。

F是G加H的和。搜索的第一個步驟的結果能夠從下面的說明中看出。在F,G和H的值被寫入在每一個方格。正如在緊挨着開始方格右側的方格上,F被打印在左上角,G被打印在左下角,而H被打印在右下角。

[圖3]

那麼,來看看其中一些方格。在有字母的方格上,G = 10,這是由於它是在一個水平方向的距離起始方格僅有一個方格。緊鄰在起始方格的上方,下方,以及左邊的方格有相同的G值10,對角線方格G值爲14。

H值是經過估計到紅色目標方格的曼哈頓距離,計算方式是僅有水平和垂直方向移動,並忽略牆上的。使用這種方法,從這個方格開始直接向右3個格就是紅格,H爲30。(譯者注:直線距離)那麼高於這個方格的方格的H值是4格距離(記住,只能水平或垂直移動)的一個H值爲40。你也許能夠看到了爲其餘方格計算H值的方法。

每一個方格的F值,再次,只是簡單地把G和H加在一塊兒的計算結果。

 

■繼續搜索

要繼續搜索,咱們簡單地選擇在開啓列表中具備最小F值的方格。而後,咱們用選定方格做如下事情:

1.把它從開啓列表取出,並添加到關閉列表。

2.檢查全部的相鄰方格。忽略那些在關閉列表裏或不能走的(牆,水或其餘非法地形),若是它們還不在開啓列表中,添加到開啓列表。將選定方格做爲新方格的「父」。

3.若是相鄰的方格已經在開啓列表,查看沿這條路徑到那個方格是不是好的。換句話說,檢查看看若是咱們使用當前方格到那裏,方格的G值是不是較低,。若是不是,什麼也不作。

另外一方面,若是新路徑的G值較低,改變相鄰方格的父到選定方格(圖中上方,改變指針的方向指向在所選擇的方格)。最後,從新計算那個方格的F值和G值。若是這彷佛使人困惑,在後面你會看到它的說明。

好吧,看看這是如何工做的。最初的9個方格,在起始方格被放到關閉列表後還有8個在開啓列表。其中,具備最低F值的是一個緊鄰起點右側的方格,其F值爲40。所以,選擇這個方格做爲下一個方格。以下圖所示高亮的藍色的部分。


[圖4]

首先,從開啓列表中刪除它,並把它添加到關閉列表(這就是它以高亮藍色顯示的緣由)。而後檢查相鄰的方格。好了,這個方格的相鄰右邊的是牆上的方格,忽略它。緊挨着左邊的是開始方格。在關閉列表上,因此也忽略它。

其他4個方格已經在開啓列表中,因此須要檢查若是使用那些方格做爲路徑是否比使用這個方格到那裏更好,將G值做爲參照點。來看看在選擇方塊右上的這個方格吧。它的G值是14,若是咱們經由當前方格到達那裏,G值將等於20(10,如今方格的G值,再加上10來垂直移到它的上面)。G值20比14高,因此這不是一個更好的路徑。若是你看一下圖能更好的理解這些。從開始方格方格沿對角線移動一個方格到那裏更直接些,而不是水平移動一個方格,再垂直移動一個方格。

當對在開啓列表中的4個相鄰方格重複做這個過程,會發現沒有路徑比當前的方格有提升,所以不改變任何東西。因此,如今,看了全部的相鄰方格,用這個方格做完檢查了,並準備移動到下一個方格。

那麼,經過開啓列表,如今減到7個方格的列表,咱們再選擇一個具備最小F值。有趣的是,在這種狀況下,有兩個方格的F值是54,那麼咱們選擇哪個呢?這其實並不重要。爲了快速的目的,選擇您最後一個添加到開啓列表中的方格能夠更快些。這種偏向的搜索比慢慢找搜索到更有同意,當你更接近目標時。但它其實並不重要。 (不一樣的處理形成了兩個版本的A *可能找到不一樣的等長路徑。)

所以,咱們選擇開始方格右下的方格,以下圖所示。

[圖5]

這一次,檢查相鄰的方格,會發現,一到右邊當即是一堵牆上的方格,因此忽略。一樣運用剛纔上面的。還忽略牆下方的方格。爲何呢?由於你不能讓方格直接從當前方格切割穿越附近的牆角。在這個過程當中你真的須要往下走,而後再挪動那個方格,繞着牆角移動。 (注:切割牆角的規則是可選的依賴於你的節點如何放置。)

那剩下5個方格。另外兩個方格低於當前方格還沒有在開啓列表中,因此將它們添加並把當前方格變成它們的父。其餘3個方格,有2個已經在關閉列表(開始方格,和一個略高於目前的方格上,在藍色突出兩個圖中),因此忽略它們。而最後的方格,眼前的當前方格左側,進行檢查,若是你去經過當前方格到那裏看是否有低的G值。沒有方格了。因此,就大功告成了,已經檢查完開啓列表中的下一個方格。

重複這個過程,直到添加目標方格到關閉列表,此時它看起來像下面的插圖。

[圖6]

在上圖中,須要注意的是開始方格下兩格方格的父已經改變。以前,它的G值爲28,指回它右上的方格。如今它有一個值爲20,並指向它上面方格。這發生在沿路徑搜索,對G值被檢查,並採用了值小一些的做爲新的路徑- 這樣父被切換,G值和F值也從新計算。在這個例子中雖然這種變化彷佛並不過重要,有不少可能的狀況,在肯定到達目標的最佳路徑時,持續的檢查將會產生很大的差別。

那麼,如何肯定路徑呢?簡單,剛開始在紅色的目標方格,並努力向父方格後移,下面的箭頭。這最終會把你帶回到開始方格,這就是你的路徑。它應該看起來像下面的插圖。移動從開始方格A到目標方格B就是從路徑上每個方格(節點)的中心移動到下一個方格的中心的問題,直到到達目標。

[圖7]

 

■A *方法總結

好了,如今經過解釋,在一個地方,展現一步一步的方法(譯者注:在這兒,把每一個步驟整理一下):

添加開始方格(或節點)到開啓列表。

重複如下操做:

a) 尋找開啓列表上最小F值的方格。將它做爲當前方格。

b) 切換到關閉列表。

c)  對於當前方格臨近的8個方格的每個....(For Each)

 

若是不能走,或者若是它在關閉列表上,忽略它。不然,執行如下操做。

若是不在開啓列表中,把它添加到開啓列表。使當前方格成爲這個方格的父。記錄的方格F值,G值和H值。

若是在開啓列表了,檢查看看採用G值來衡量這個路徑到那個方格是不是更好的。更低的G值意味着這是一個更好的路徑。若是是這樣,把方格的父改成當前方格,並從新計算方格的G值和F值。若是你保持開啓列表按F值排序,因爲這個變化你可能需重存列表。

d)當你中止:

在目標方格添加到關閉列表的狀況下,路徑已經被發現(見下面的注),或沒法找到目標方格,而且開啓列表是空的。在這種狀況下,不存在路徑。

保存路徑。從目標方格往回走,從每一個方格移到其父,直到到達開始方格。這是想要的路徑。

注:在早期版本的文章中,有人建議,當目標方格(或節點)已經添加到開啓列表,而不是關閉的列表,你就能夠停下來。這樣作會更快,它幾乎老是會給你的最短路徑,但並不是老是如此。有些狀況下,當從第二移動到最後一個節點到最後的(目標)節點的運動成本可能有明顯變化時,這樣作可能產生影響--例如,若是河流在兩個節點之間交叉的狀況下。

 

■小「憤」

請原諒題外話,但值得指出的是,當在網上閱讀的A *路徑搜索,並在各種論壇上的各類討論時,偶爾會看到有人提到某些代碼不是A *。對於A *使用方法,須要包含上面討論到的元素 -- 特別是開放列表和關閉列表和路徑採用F值,G值和H值。有不少其餘的路徑搜索算法,一般被認爲是最好的方法但不是A *。在本文的末尾有布萊恩斯托特的討論,包括他們的不少一些利弊引用的文章。有時替代品在某些狀況下更好,但你應該明白你是正在進入的。(譯者注:別被誤導薰心)好了,爽了。回到話題。

 

■實施上的注意事項

如今您瞭解了基本的方法,當你編寫本身的程序時,有一些額外的事情要考慮。下面給出我用C ++和Blitz Basic編寫的程序,用其餘語言也一樣有效。

1.其餘單元(防止碰撞):若是你碰巧仔細看個人演示代碼,你會注意到它徹底忽略了屏幕上的其餘單元。這些單元彼此穿過。根據遊戲,這多是能夠的,多是不能夠的。若是在路徑搜索算法裏想考慮其餘單元,並讓它們彼此走動,我建議你只考慮中止的單元或路徑搜索附近計算路徑的單元,用不能走來處理他們的當前位置。對於正在移動的相鄰單元,能夠經過處罰沿着各自路徑的節點阻止碰撞,從而促使路徑尋找單元找到替代路徑。(在#2有更多的描述)。

若是選擇考慮正在移動的單元和路徑尋找上不相鄰的其餘單元,將須要開發一種方法來預測他們會在任何給定的時間點,使他們可以獲得適當的迴避。不然,你極可能會有用曲折來避免什麼也沒有的其餘單元的奇怪的路徑。

你還會,固然,須要開發一些碰撞檢測代碼,由於不管多麼好的路徑在它的計算時,事情可能隨時間而改變。當發生碰撞時的單位必需要麼計算新的路徑,或者若是其餘單元是移動且不是一個迎面碰撞,在當前路徑繼續以前等待其餘單位經過。

這些技巧多是足以讓你開始。若是您想了解更多,這裏有一些你可能會發現有用的連接:

角色的轉向行爲:

http://www.red3d.com/cwr/steer/

克雷格雷諾的方向盤上的工做是從路徑搜索有點不一樣,但它能夠與路徑搜索集成,以作出更完整的移動和防撞系統。

計算機遊戲中的長短轉向:

http://ducati.doc.ntu.ac.uk/uksim/uksim%2704/Papers/Simon%20Tomlinson-%2004-20/paper04-20%20CR.pdf

在轉向和路徑搜索的一個有趣的調查。這是一個PDF文件。

協調機組運行:

http://www.gamasutra.com/features/game_design/19990122/movement_01.htm

由帝國時代的設計師戴夫·乍的兩部分組成的第一系列在造成和基於組的運動。

實現協調運動:

http://www.gamasutra.com/view/feature/3314/implementing_coordinated_movement.php

戴夫·乍的兩部分組成的第二系列。

 

2.多樣的地造成本:在本教程和我附隨的程序中,地形僅僅是兩件事情之一 – 能走和不能走。可是,若是雖然有能走的地形,可是須要更高的移動成本?沼澤,丘陵,地下城的樓梯,等等 - 這些都是能走的地形的例子,但成本比平坦的開闊地要高。相似地,道路可能具備較低的運行成本比周圍的地形。

這個問題很容易經過任何給定節點的G值加地造成本的計算處理來實現。簡單地添加一個額外的成本到這樣的節點。A *路徑搜索算法是用來尋找最低成本路徑,應該很容易地處理這個問題。在我描述的簡單的例子中,當地形只有能走和不能走,A *將查找最短,最直接的路徑。可是,在可變成本的地形環境中,以最少的成本路徑可能行走了較長的距離 - 就像繞過的沼澤道路,而不是直接經過它。

一個有趣的附加考慮是專業人士稱之爲「影響映射」 。正如上述的可變成本的地形,你能夠建立一個額外的積分系統,並將其應用到AI的路徑。試想一下,你有一些穿過山區的單元的地圖。每當計算機發送通某人經過路徑時,它被重擊。若是你願意,你能夠建立一個發生大量屠殺來處罰節點的影響地圖。這會教電腦偏袒安全的路徑,並幫助它避免愚蠢的狀況下,它經過一個特定的路徑不斷派遣軍隊,只是由於它是短(但更危險)。

另外一種可能的用法是懲罰沿着路徑附近移動中的節點。A *的其中一個缺點是,當一組的單元全都嘗試找到的相似位置的路徑,一般有一個顯著程度的重疊,與一個或多個單元試圖利用相同或相似的路線到它們的目的地。添加一個已經被其餘單元「叫停」點球節點將有助於確保必定程度的分離,並減小碰撞。不要把這樣的節點視爲不能走,然而由於你還願意多個單元可以依次擠過狹窄的通道,若是有必要的。此外,你應該只處罰路徑搜索附近的單元,不是全部的路徑,不然你會獲得避免單元的單元的奇怪躲避行爲,都遠不及他們當時的路徑。此外,你應該只懲罰節點沿着一條當前或將來的路徑的一部分,而不是已經訪問過並留下之前的路徑節點。

3.處理未探索區域:你曾經玩過一款PC遊戲,計算機老是準確的知道路該如何走,即便地圖尚未被探索?根據不一樣的遊戲,總獲得那樣好的路徑搜索是不現實的。幸運的是,這是很容易處理的問題。

答案是建立一個獨立的「已知的經過性」數組爲每一個各類各樣的玩家以及電腦對手的(每一個玩家,不是每個單元 - 那將須要大量的計算機內存)。每一個數組將包含有關該玩家已探索區域的信息,與地圖的其餘部分直到證實假設爲是可行的。使用這種方法,單元將漫步死角,使相似的錯誤選擇,直到他們發現周圍的路。一旦地圖被探索,然而,路徑搜索會正常工做。

4.更平滑的路徑:雖然A *會自動給出最短,成本最低的路徑,它不會自動給出看起來最平滑的路徑。看一看例子(圖7)計算的最終路徑。在該路徑中,第一個步驟以後是到開始方格的右側。若是第一步是從起點的正下方,咱們的路徑不更更平滑了些嗎?

有幾種方法來解決這個問題。當你正在計算路徑,你能夠處罰那裏些方向有變化的節點,增長了處罰他們的G值扣分。或者,你能夠在計算後瀏覽你的路徑,尋找在選擇相鄰節點的地方會給你一個看起來更好的路徑。欲瞭解更多關於整個問題,看看向更加逼真路徑搜索(Toward More Realistic Pathfinding),一個(免費的,但須要註冊)在Gamasutra.com上Macro Pinter的文章。

5.非方格搜索區域:在咱們的例子中,咱們使用了一個簡單的二維方格佈局。你並不須要使用這種方法。你可使用不規則的形狀區域。想一想風險的棋盤遊戲,以及在遊戲中的國家。你能夠設計一個路徑搜索方案給像那樣的遊戲。要作到這一點,你須要建立一個表,用於存儲毗鄰的國家,並與移動從一個國家到下一個相關的G值。你還須要拿出用於估計H.其餘一切會被處理同樣在上面的例子中的方法。而不是使用相鄰的方格,在增長新的項目到開啓列表時在表中你會簡單地查找到相鄰國家。

一樣,你能夠爲一個固定的地形圖建立路徑的路標系統。路標一般走過的路徑上的點,也許在一個地牢的道路或關鍵的隧道上。做爲遊戲設計者,你能預先指定這些路點。兩個路標會被認爲是「相鄰」彼此是否有它們之間的直線路徑上沒有障礙。因爲在風險的例子,您將節省在某種類型的查找表這個鄰接信息,並用它生成新的開啓列表項目時。那麼你會記錄相關的G值(可能經過使用節點間的直線距離)和H成本(可能使用從節點到目標的直線距離)。一切將繼續如常。

阿米特·帕特爾還寫了一個簡短的文章鑽研一些替代品。對於使用非方形的搜索區域上等距RPG地圖搜索的另外一個例子,看看個人文章兩層的A *路徑搜索(http://www.policyalmanac.org/games/twoTiered.htm)。

6.一些超速提示:當你開發本身的A *程序,或者改編我寫的,你最終會發現路徑搜索使用你的CPU時間大幅大塊,特別是若是你對至關大數量的路徑搜索單元的板和一個至關大的地圖。若是你在網上讀過的東西了,你會發現,這是真實的,即便設計像星際爭霸或帝國時代遊戲的專業人士。若是你看到的東西開始放緩,因爲路徑搜索,這裏有一些想法,可能會加快速度:

■考慮一個小地圖或更少的單位。

永遠不要作一次幾個單元的路徑搜索。相反,把它們放在一個隊列,它們分佈在幾個遊戲循環。若是你的遊戲在運行時,好比說,每秒40個週期運行,沒有人會注意到。但他們會發現,當在同一時間一羣單元都在計算路徑時遊戲彷佛在一段時間放慢每一次。

請考慮使用更大的方格(或者任何你正在使用的形狀)爲您的地圖。這減小了搜索以找到的路徑的節點的總數。若是你有雄心,能夠設計出了用於在不一樣的狀況下,這取決於路徑的長度的兩個或更多個路徑搜索系統。這是專業人士作的,使用大面積的長路徑,而後切換到更精細的使用較小的方格/地區搜索,當你接近目標。若是你有興趣在這個概念,看看個人文章兩個層次的A *路徑搜索。

對於更長的路徑,考慮修訂是硬鏈接到遊戲預先計算好的路徑。

考慮預處理地圖找出哪些領域是從地圖的其他部分沒法訪問。我把這些領域的「孤島」。在現實中,他們能夠是島嶼或者其餘任何地區,是另有圍牆關閉,沒法訪問。其中A *的缺點之一是,若是你告訴它來尋找路徑等方面,它會搜索整個地圖,停車,只有當每平方訪問/節點已經過打開和關閉名單處理。這會浪費大量的CPU時間。它能夠經過預先肯定哪些地區是不可訪問(經過洪水填充或相似的程序),記錄在某種類型的陣列信息,而後在開始路徑搜索前檢查它來預防。

在擁擠的,迷宮似的環境中,考慮節點標記不隨地致使的死角。這些區域能夠手動預先指定的地圖編輯器,或者若是你有雄心的,你能夠開發一個算法,自動識別等領域。在給定的死衚衕區域節點的任何集合能夠賦予一個惟一的識別號碼。而後路徑搜索時,只停下來考慮一個死衚衕區域節點,若是起始位置或目的地剛好是在特定的死衚衕區問題,你能夠放心地忽略全部的死角。

7.維護開啓列表:這其實是A *路徑搜索算法中最耗費時間的元素之一。您能夠訪問開啓列表時,都須要找到具備最小F值的方格。有幾種方法能夠作到這一點。根據須要,你能夠保存路徑項目,每次當你須要找到最小F值的方格時,簡單的遍歷整個列表。這是簡單的,但對於長路徑很慢。這能夠經過維護一個排序的列表,每次須要最小F-成本方形時間只需抓住了第一個項目從名單獲得改善。當我寫個人程序,這是我用第一種方法。

這將工做得至關好爲小地圖,但它不是最快答案。嚴重的A *程序員誰想要真正的速度使用一種叫作二進制堆,這是我在個人代碼中使用。在個人經驗,這種方法將是至少2-3倍的速度在大多數狀況下,而且在幾何形狀更快(快10+次)上較長的路徑。若是你主動去尋找更多關於二叉堆,看看個人文章,在A *路徑搜索使用二進制堆(http://www.policyalmanac.org/games/binaryHeaps.htm)。

另外一種可能的瓶頸是你的方式明確和維護路徑搜索調用之間的數據結構。我我的更喜歡存儲全部陣列。雖然節點能夠生成,記錄並保存在一個動態的,面向對象的方式,我發現,建立和刪除這些對象所需的時間量增長了額外的開銷,沒必要要的水平會減慢速度。若是你使用數組,不過,你須要調用之間乾淨的東西了。你會想在這種狀況下的最後一件事就是花零時間作完一切了在調用路徑搜索後,特別是若是你有一個大的地圖。

我避免這種開銷經過建立一個二維數組稱爲whichList(X,Y),其指定在每一個節點上個人地圖做爲任一開啓列表或關閉列表上。路徑搜索的嘗試以後,我不歸零數組。相反,我在每個路徑搜索呼叫復位onClosedList和onOpenList的價值觀,每一個路徑嘗試尋找相似+5什麼都遞增。經過這種方式,算法能夠放心地忽略垃圾從之前的路徑搜索的嘗試遺留任何數據。我也喜歡存放F,G和H陣列的成本值。在這種狀況下,我只是寫在任何預先存在的價值和不打擾清除陣列時,我作的。

在多個陣列存儲數據佔用更多的內存,雖然如此,有一個權衡。最終,你應該使用什麼方法,你是最舒服的。

8. Dijkstra的算法:當A *一般被認爲是最好的路徑搜索算法(見上面的小憤),存在至少一個其它的算法有其用途 - Dijkstra算法。 Dijkstra的是基本相同的A *,除了沒有啓發式(H始終爲0)。由於它沒有啓發式,它經過在每個方向一樣擴大了搜索。正如你可能想象的,由於這Dijkstra算法一般是結束了探索一個更大的區域以前目標被發現。這一般使得它比A *慢。

那麼,爲何使用它?有時候,咱們不知道咱們的目標位置是。假設你有一個須要去得到某種資源的一些資源收集裝置。它可能知道幾個資源區域,但它但願去最近的一個。在這裏,Dijkstra的比A *更好,由於咱們不知道哪個是最接近的。咱們惟一的選擇是重複使用A *查找到每個的距離,而後選擇這條道路。可能有無數相似的狀況,咱們知道那種位置,咱們可能會尋找的,想找到最近的一個,但不知道它在哪裏或哪個多是最接近的。

 

■延伸閱讀

好了,如今你已具有了基礎知識和一些先進的概念。在這一點上,我建議你到涉水個人源代碼。該軟件包裏有兩個版本,一個是C ++的,一個是Blitz Basic的。兩個版本都有大量註釋,相對來講應該是至關容易跟上理解。這裏是連接。

http://www.blitzcoder.com/cgi-bin/showcase/showcase_showentry.pl?id=turtle177604062002002208&comments=no"

(譯者注:這個連接如今已經不能用了,請用:http://www.policyalmanac.org/games/AStar.zip)

演示代碼:A *探路者(2維)1.9版

若是您沒有接觸到C ++或Blitz Basic,兩個小的EXE文件能夠在C ++版本中找到。Blitz Basic版本能夠經過在Blitz Basic網站下載Blitz Basic 3D(不加Blitz Plus)的免費試用版原本運行。

你也應該考慮經過如下網頁閱讀。若是你已經閱讀本教程,如今他們要容易明白得多。

Amit的A *頁:

http://www-cs-students.stanford.edu/~amitp/gameprog.html#Paths

這是一個由阿米特帕特爾寫的有很是普遍引用的頁面,若是你尚未看過本文,就看它可能有點混亂。很是值得一試。尤爲是Amit本身的想法的話題。

智能移動:智能路徑查找:

http://www.gamasutra.com/view/feature/3215/myths_and_facts_in_avoiding_.php

本文由布賴恩·斯托特在須要註冊閱讀的Gamasutra.com發佈的。註冊是免費的,很值得去看看,更不用說那些可用的資源。由布萊恩用Delphi編寫的幫助我學習A *程序,它是個人A *程序背後的靈感。它也介紹了一些A *替代品。

地形分析:

http://www.gamasutra.com/features/gdcarchive/2000/pottinger.doc

這是一種先進的,且頗有趣,文章由涉獵全面的工做室的專家Dave Pottinger撰寫。這傢伙協調過帝國時代和世紀國王的開發。不要期望在這裏明白了一切,但它是一個有趣的文章,可能會給你一些本身的想法。它包括Mipmapping(譯者注:三維計算機圖形的貼圖渲染中有一個經常使用的技術),影響映射,還有其它一些高級AI /路徑搜索的概念進行了。

其餘一些關於路徑搜索的網站值得一試(譯者注:基本已不能訪問):

aiGuru: Pathfinding

Game AI Resource:Pathfinding

GameDev.net:Pathfinding

好了,就是這樣。我很想到你使用這些概念編寫程序。我能夠經過郵箱收到。

pwlester@policyalmanac.org

 

在置筆以前,祝你好運!

相關文章
相關標籤/搜索