版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、序:搜索區(qū)域假設(shè)有人想從A點移動到一墻之隔的B點,如下圖,綠色的是起點A,紅色是終點B,藍(lán)色方塊是中間的墻。圖1你首先注意到,搜索區(qū)域被我們劃分成了方形網(wǎng)格。像這樣,簡化搜索區(qū)域,是尋路的第一步。這一方法把搜索區(qū)域簡化成了一個二維數(shù)組。數(shù)組的每一個元素是網(wǎng) 格的一個方塊,方塊被標(biāo)記為可通過的和不可通過的。路徑被描述為從A到B我們經(jīng)過的方塊的集合。一旦路徑被找到,我們的人就從一個方格的中心走向另一個, 直到到達(dá)目的地。這些中點被稱為“節(jié)點”。當(dāng)你閱讀其他的尋路資料時,你將經(jīng)常會看到人們討論節(jié)點。為什么不把他們描述為方格呢?因為有可能你的路徑被分割成其他不是方格 的結(jié)構(gòu)。他們完全可以是矩形,六角形
2、,或者其他任意形狀。節(jié)點能夠被放置在形狀的任意位置可以在中心,或者沿著邊界,或其他什么地方。我們使用這種系 統(tǒng),無論如何,因為它是最簡單的。開始搜索正如我們處理上圖網(wǎng)格的方法,一旦搜索區(qū)域被轉(zhuǎn)化為容易處理的節(jié)點,下一步就是去引導(dǎo)一次找到最短路徑的搜索。在A*尋路算法中,我們通過從點A開始,檢查相鄰方格的方式,向外擴(kuò)展直到找到目標(biāo)。我們做如下操作開始搜索: 1,從點A開始,并且把它作為待處理點存入一個“開啟列表”。開啟列表就像一張購物清單。盡管現(xiàn)在列表里只有一個元素,但以后就會多起來。你的路徑可能會通過它包含的方格,也可能不會?;旧?,這是一個待檢查方格的列表。
3、; 2,尋找起點周圍所有可到達(dá)或者可通過的方格,跳過有墻,水,或其他無法通過地形的方格。也把他們加入開啟列表。為所有這些方格保存點A作為“父方格”。當(dāng)我們想描述路徑的時候,父方格的資料是十分重要的。后面會解釋它的具體用途。 3,從開啟列表中刪除點A,把它加入到一個“關(guān)閉列表”,列表中保存所有不需要再次檢查的方格。在這一點,你應(yīng)該形成如圖的結(jié)構(gòu)。在圖中,暗綠色方格是你起始方格的中心。它被用淺藍(lán)色描邊,以表示它被加入到關(guān)閉列表中了。所有的相鄰格現(xiàn)在都在開啟列表中,它們被用淺綠色描邊。每個方格都有一個灰色指針反指他們的父方格,也就是開始的方格。圖2接著,我們選擇開
4、啟列表中的臨近方格,大致重復(fù)前面的過程,如下。但是,哪個方格是我們要選擇的呢?是那個F值最低的。路徑評分選擇路徑中經(jīng)過哪個方格的關(guān)鍵是下面這個等式:F = G + H這里: * G = 從起點A,沿著產(chǎn)生的路徑,移動到網(wǎng)格上指定方格的移動耗費(fèi)。 * H = 從網(wǎng)格上那個方格移動到終點B的預(yù)估移動耗費(fèi)。這經(jīng)常被稱為啟發(fā)式的,可能會讓你有點迷惑。這樣叫的原因是因為它只是個猜測。我們沒辦法事先知道路徑的長 度,因為路上可能存在各種障礙(墻,水,等等)。雖然本文只提供了一種計算H的方法,但是你可以在網(wǎng)上找到很多其他的方法。我們的路
5、徑是通過反復(fù)遍歷開啟列表并且選擇具有最低F值的方格來生成的。文章將對這個過程做更詳細(xì)的描述。首先,我們更深入的看看如何計算這個方程。正如上面所說,G表示沿路徑從起點到當(dāng)前點的移動耗費(fèi)。在這個例子里,我們令水平或者垂直移動的耗費(fèi)為10,對角線方向耗費(fèi)為14。我們?nèi)∵@些值是因為沿 對角線的距離是沿水平或垂直移動耗費(fèi)的的根號2(別怕),或者約1.414倍。為了簡化,我們用10和14近似。比例基本正確,同時我們避免了求根運(yùn)算和 小數(shù)。這不是只因為我們怕麻煩或者不喜歡數(shù)學(xué)。使用這樣的整數(shù)對計算機(jī)來說也更快捷。你不就就會發(fā)現(xiàn),如果你不使用這些簡化方法,尋路會變得很慢。既然我們在計算沿特定路徑通往某個方格的
6、G值,求值的方法就是取它父節(jié)點的G值,然后依照它相對父節(jié)點是對角線方向或者直角方向(非對角線),分別增加14和10。例子中這個方法的需求會變得更多,因為我們從起點方格以外獲取了不止一個方格。H值可以用不同的方法估算。我們這里使用的方法被稱為曼哈頓方法,它計算從當(dāng)前格到目的格之間水平和垂直的方格的數(shù)量總和,忽略對角線方向。然后把結(jié)果乘 以10。這被成為曼哈頓方法是因為它看起來像計算城市中從一個地方到另外一個地方的街區(qū)數(shù),在那里你不能沿對角線方向穿過街區(qū)。很重要的一點,我們忽略了 一切障礙物。這是對剩余距離的一個估算,而非實際值,這也是這一方法被稱為啟發(fā)式的原因。想知道更多?你可以在這里找到方程和
7、額外的注解。F的值是G和H的和。第一步搜索的結(jié)果可以在下面的圖表中看到。F,G和H的評分被寫在每個方格里。正如在緊挨起始格右側(cè)的方格所表示的,F(xiàn)被打印在左上角,G在左下角,H則在右下角。圖3現(xiàn)在我們來看看這些方格。寫字母的方格里,G = 10。這是因為它只在水平方向偏離起始格一個格距。緊鄰起始格的上方,下方和左邊的方格的G值都等于10。對角線方向的G值是14。H值通過求解到紅色目標(biāo)格的曼哈頓距離得到,其中只在水平和垂直方向移動,并且忽略中間的墻。用這種方法,起點右側(cè)緊鄰的方格離紅色方格有3格距離,H值 就是30。這塊方格上方的方格有4格距離(記住,只能在水平和垂直方向移動),H值是40。你大致
8、應(yīng)該知道如何計算其他方格的H值了。每個格子的F值,還是簡單的由G和H相加得到繼續(xù)搜索為了繼續(xù)搜索,我們簡單的從開啟列表中選擇F值最低的方格。然后,對選中的方格做如下處理: 4,把它從開啟列表中刪除,然后添加到關(guān)閉列表中。 5,檢查所有相鄰格子。跳過那些已經(jīng)在關(guān)閉列表中的或者不可通過的(有墻,水的地形,或者其他無法通過的地形),把他們添加進(jìn)開啟列表,如果他們還不在里面的話。把選中的方格作為新的方格的父節(jié)點。 6,如果某個相鄰格已經(jīng)在開啟列表里了,檢查現(xiàn)在的這條路徑是否更好。換句話說,檢查如果我們用新的路徑到達(dá)它的話,G值是否
9、會更低一些。如果不是,那就什么都不做。 另一方面,如果新的G值更低,那就把相鄰方格的父節(jié)點改為目前選中的方格(在上面的圖表中,把箭頭的方向改為指向這個方格)。最后,重新計算F和G的值。如果這看起來不夠清晰,你可以看下面的圖示。好了,讓我們看看它是怎么運(yùn)作的。我們最初的9格方格中,在起點被切換到關(guān)閉列表中后,還剩8格留在開啟列表中。這里面,F(xiàn)值最低的那個是起始格右側(cè)緊鄰的格子,它的F值是40。因此我們選擇這一格作為下一個要處理的方格。在緊隨的圖中,它被用藍(lán)色突出顯示。圖4首先,我們把它從開啟列表中取出,放入關(guān)閉列表(這就是他被藍(lán)色突出顯
10、示的原因)。然后我們檢查相鄰的格子。哦,右側(cè)的格子是墻,所以我們略過。左側(cè)的格子是起始格。它在關(guān)閉列表里,所以我們也跳過它。其他4格已經(jīng)在開啟列表里了,于是我們檢查G值來判定,如果通過這一格到達(dá)那里,路徑是否更好。我們來看選中格子下面的方格。它的G值是14。如果我們從 當(dāng)前格移動到那里,G值就會等于20(到達(dá)當(dāng)前格的G值是10,移動到上面的格子將使得G值增加10)。因為G值20大于14,所以這不是更好的路徑。如 果你看圖,就能理解。與其通過先水平移動一格,再垂直移動一格,還不如直接沿對角線方向移動一格來得簡單。當(dāng)我們對已經(jīng)存在于開啟列表中的4個臨近格重復(fù)這一過程的時候,我們發(fā)現(xiàn)沒有一條路徑可以
11、通過使用當(dāng)前格子得到改善,所以我們不做任何改變。既然我們已經(jīng)檢查過了所有鄰近格,那么就可以移動到下一格了。于是我們檢索開啟列表,現(xiàn)在里面只有7格了,我們?nèi)匀贿x擇其中F值最低的。有趣的是,這次,有兩個格子的數(shù)值都是54。我們?nèi)绾芜x擇?這并不麻煩。從速度 上考慮,選擇最后添加進(jìn)列表的格子會更快捷。這種導(dǎo)致了尋路過程中,在靠近目標(biāo)的時候,優(yōu)先使用新找到的格子的偏好。但這無關(guān)緊要。(對相同數(shù)值的不同對 待,導(dǎo)致不同版本的A*算法找到等長的不同路徑。)那我們就選擇起始格右下方的格子,如圖。圖5這次,當(dāng)我們檢查相鄰格的時候,發(fā)現(xiàn)右側(cè)是墻,于是略過。上面一格也被略過。我們也略過了墻下面的格子。為什么呢?因為
12、你不能在不穿越墻角的情況下直接到 達(dá)那個格子。你的確需要先往下走然后到達(dá)那一格,按部就班的走過那個拐角。(注解:穿越拐角的規(guī)則是可選的。它取決于你的節(jié)點是如何放置的。)這樣一來,就剩下了其他5格。當(dāng)前格下面的另外兩個格子目前不在開啟列表中,于是我們添加他們,并且把當(dāng)前格指定為他們的父節(jié)點。其余3格,兩個已經(jīng)在關(guān) 閉列表中(起始格,和當(dāng)前格上方的格子,在表格中藍(lán)色高亮顯示),于是我們略過它們。最后一格,在當(dāng)前格的左側(cè),將被檢查通過這條路徑,G值是否更低。不 必?fù)?dān)心,我們已經(jīng)準(zhǔn)備好檢查開啟列表中的下一格了。我們重復(fù)這個過程,直到目標(biāo)格被添加進(jìn)關(guān)閉列表(注解),就如在下面的圖中所看到的。圖6注意,起
13、始格下方格子的父節(jié)點已經(jīng)和前面不同的。之前它的G值是28,并且指向右上方的格子。現(xiàn)在它的G值是20,指向它上方的格子。這在尋路過程中的某 處發(fā)生,當(dāng)應(yīng)用新路徑時,G值經(jīng)過檢查變得低了于是父節(jié)點被重新指定,G和F值被重新計算。盡管這一變化在這個例子中并不重要,在很多場合,這種變化會 導(dǎo)致尋路結(jié)果的巨大變化。那么,我們怎么確定這條路徑呢?很簡單,從紅色的目標(biāo)格開始,按箭頭的方向朝父節(jié)點移動。這最終會引導(dǎo)你回到起始格,這就是你的路徑!看起來應(yīng)該像圖中那樣。從起始格A移動到目標(biāo)格B只是簡單的從每個格子(節(jié)點)的中點沿路徑移動到下一個,直到你到達(dá)目標(biāo)點。就這么簡單。圖7A*方法總結(jié)好,現(xiàn)在你已經(jīng)看完了整
14、個說明,讓我們把每一步的操作寫在一起: 1,把起始格添加到開啟列表。 2,重復(fù)如下的工作: a) 尋找開啟列表中F值最低的格子。我們稱它為當(dāng)前格。 b) 把它切換到關(guān)閉列表。 c) 對相鄰的8格中的每一個? * 如果它不可通過或者已經(jīng)在關(guān)閉列表中,略過它。反之如下
15、。 * 如果它不在開啟列表中,把它添加進(jìn)去。把當(dāng)前格作為這一格的父節(jié)點。記錄這一格的F,G,和H值。 * 如果它已經(jīng)在開啟列表中,用G值為參考檢查新的路徑是否更好。更低的G值意味著更好的路徑。如果是這樣,就把這一格的父節(jié)點改成當(dāng)前格,并且重新計算這一格的G和F值。如果你保持你的開啟列表按F值排序,改變之后你可能需要重新對開啟列表排序。
16、 d) 停止,當(dāng)你 * 把目標(biāo)格添加進(jìn)了關(guān)閉列表(注解),這時候路徑被找到,或者 * 沒有找到目標(biāo)格,開啟列表已經(jīng)空了。這時候,路徑不存在。 3.保存路徑。從目標(biāo)格開始,沿著每一格的父節(jié)點移動直到回到起始格。這就是你的路徑。(注解:在這篇文章的較早版本中,建議的做法是當(dāng)目標(biāo)格(或節(jié)點)被加入到開啟列表,而不是關(guān)閉列表的時候停止尋路。這么做會更迅速
17、,而且?guī)缀蹩偸悄苷业阶疃痰穆窂剑皇墙^對的。當(dāng)從倒數(shù)第二個節(jié)點到最后一個(目標(biāo)節(jié)點)之間的移動耗費(fèi)懸殊很大時例如剛好有一條河穿越兩個節(jié)點中間,這時候舊的做法和新的做法就會有顯著不同。)題外話離題一下,見諒,值得一提的是,當(dāng)你在網(wǎng)上或者相關(guān)論壇看到關(guān)于A*的不同的探討,你有時會看到一些被當(dāng)作A*算法的代碼而實際上他們不是。要使用A*, 你必須包含上面討論的所有元素特定的開啟和關(guān)閉列表,用F,G和H作路徑評價。有很多其他的尋路算法,但他們并不是A*,A*被認(rèn)為是他們當(dāng)中最好 的。Bryan Stout在這篇文章后面的參考文檔中論述了一部分,包括他們的一些優(yōu)點和缺點。有時候特定的場合其他算法會更好
18、,但你必須很明確你在作什么。好了,夠多 的了?;氐轿恼?。實現(xiàn)的注解現(xiàn)在你已經(jīng)明白了基本原理,寫你的程序的時候還得考慮一些額外的東西。下面這些材料中的一些引用了我用C+和Blitz Basic寫的程序,但對其他語言寫的代碼同樣有效。1.其他單位(避免碰撞):如果你恰好看了我的例子代碼,你會發(fā)現(xiàn)它完全忽略了其他單位。我的尋路者事實上可以相互穿越。取決于具體的游戲,這也許可以, 也許不行。如果你打算考慮其他單位,希望他們能互相繞過,我建議你只考慮靜止或那些在計算路徑時臨近當(dāng)前單位的單位,把它們當(dāng)前的位置標(biāo)志為可通過的。對 于臨近的運(yùn)動著的單位,你可以通過懲罰它們各自路徑上的節(jié)點,來鼓勵這些尋路者找到
19、不同的路徑(更多的描述見#2).如果你選擇了把其他正在移動并且遠(yuǎn)離當(dāng)前尋路單位的那些單位考慮在內(nèi),你將需要實現(xiàn)一種方法及時預(yù)測在何時何地碰撞可能會發(fā)生,以便恰當(dāng)?shù)谋苊狻7駝t你極有可能得到一條怪異的路徑,單位突然轉(zhuǎn)彎試圖避免和一個已經(jīng)不存在的單位發(fā)生碰撞。當(dāng)然,你也需要寫一些碰撞檢測的代碼,因為無論計算的時候路徑有多完美,它也會因時間而改變。當(dāng)碰撞發(fā)生時,一個單位必須尋找一條新路徑,或者,如果另一個單位正在移動并且不是正面碰撞,在繼續(xù)沿當(dāng)前路徑移動之前,等待那個單位離開。這些提示大概可以讓你開始了。如果你想了解更多,這里有些你可能會覺得有用的鏈接: * 自治角
20、色的指導(dǎo)行為:Craig Reynold在指導(dǎo)能力上的工作和尋路有些不同,但是它可以和尋路整合從而形成更完整的移動和碰撞檢測系統(tǒng)。 * 電腦游戲中的長短距指導(dǎo):指導(dǎo)和尋路方面著作的一個有趣的考察。這是一個pdf文件。 * 協(xié)同單位移動:一個兩部分系列文章的第一篇,內(nèi)容是關(guān)于編隊和基于分組的移動,作者是帝國時代(Age of Empires)的設(shè)計者Dave Pottinger. * 實現(xiàn)協(xié)同移動:Dave Pottinger文章系列的第二篇。2. 不同的地形損耗:在這個教程和我附帶的程序
21、中,地形只能是二者之可通過的和不可通過的。但是你可能會需要一些可通過的地形,但是移動耗費(fèi)更高沼澤,小 山,地牢的樓梯,等等。這些都是可通過但是比平坦的開闊地移動耗費(fèi)更高的地形。類似的,道路應(yīng)該比自然地形移動耗費(fèi)更低。這個問題很容易解決,只要在計算任何地形的G值的時候增加地形損耗就可以了。簡單的給它增加一些額外的損耗就可以了。由于A*算法已經(jīng)按照尋找最低耗費(fèi)的 路徑來設(shè)計,所以很容易處理這種情況。在我提供的這個簡單的例子里,地形只有可通過和不可通過兩種,A*會找到最短,最直接的路徑。但是在地形耗費(fèi)不同的 場合,耗費(fèi)最低的路徑也許會包含很長的移動距離就像沿著路繞過沼澤而不是直接穿過它。一種需額外考
22、慮的情況是被專家稱之為“influence mapping”的東西(暫譯為影響映射圖)。就像上面描述的不同地形耗費(fèi)一樣,你可以創(chuàng)建一格額外的分?jǐn)?shù)系統(tǒng),并把它應(yīng)用到尋路的AI中。假設(shè)你有一張 有大批尋路者的地圖,他們都要通過某個山區(qū)。每次電腦生成一條通過那個關(guān)口的路徑,它就會變得更擁擠。如果你愿意,你可以創(chuàng)建一個影響映射圖對有大量屠殺 事件的格子施以不利影響。這會讓計算機(jī)更傾向安全些的路徑,并且?guī)椭苊饪偸莾H僅因為路徑短(但可能更危險)而持續(xù)把隊伍和尋路者送到某一特定路徑。另一個可能得應(yīng)用是懲罰周圍移動單位路徑上得節(jié)點。A*的一個底限是,當(dāng)一群單位同時試圖尋路到接近的地點,這通常會導(dǎo)致路徑交疊
23、。以為一個或者多個單位 都試圖走相同或者近似的路徑到達(dá)目的地。對其他單位已經(jīng)“認(rèn)領(lǐng)”了的節(jié)點增加一些懲罰會有助于你在一定程度上分離路徑,降低碰撞的可能性。然而,如果有必 要,不要把那些節(jié)點看成不可通過的,因為你仍然希望多個單位能夠一字縱隊通過擁擠的出口。同時,你只能懲罰那些臨近單位的路徑,而不是所有路徑,否則你就 會得到奇怪的躲避行為例如單位躲避路徑上其他已經(jīng)不在那里的單位。 還有,你應(yīng)該只懲罰路徑當(dāng)前節(jié)點和隨后的節(jié)點,而不應(yīng)處理已經(jīng)走過并甩在身后的節(jié)點。3. 處理未知區(qū)域:你是否玩過這樣的PC游戲,電腦總是知道哪條路是正確的,即使它還沒有偵察過地圖?對于游戲,尋路太好會顯得不真實。幸運(yùn)的是,
24、這是一格可以輕易解決的問題。答案就是為每個不同的玩家和電腦(每個玩家,而不是每個單位那樣的話會耗費(fèi)大量的內(nèi)存)創(chuàng)建一個獨(dú)立的“knownWalkability”數(shù)組,每 個數(shù)組包含玩家已經(jīng)探索過的區(qū)域,以及被當(dāng)作可通過區(qū)域的其他區(qū)域,直到被證實。用這種方法,單位會在路的死端徘徊并且導(dǎo)致錯誤的選擇直到他們在周圍找到 路。一旦地圖被探索了,尋路就像往常那樣進(jìn)行。4. 平滑路徑:盡管A*提供了最短,最低代價的路徑,它無法自動提供看起來平滑的路徑??匆幌挛覀兊睦幼罱K形成的路徑(在圖7)。最初的一步是起始格的右下方,如果這一步是直接往下的話,路徑不是會更平滑一些嗎?有幾種方法來解決這個問題。當(dāng)計算路徑
25、的時候可以對改變方向的格子施加不利影響,對G值增加額外的數(shù)值。也可以換種方法,你可以在路徑計算完之后沿著它跑一遍,找那些用相鄰格替換會讓路徑看起來更平滑的地方。想知道完整的結(jié)果,查看Toward More Realistic Pathfinding,一篇(免費(fèi),但是需要注冊)Marco Pinter發(fā)表在G的文章5. 非方形搜索區(qū)域:在我們的例子里,我們使用簡單的2D方形圖。你可以不使用這種方式。你可以使用不規(guī)則形狀的區(qū)域。想想冒險棋的游戲,和游戲中那些國家。 你可以設(shè)計一個像那樣的尋路關(guān)卡。為此,你可能需要建立一個國家相鄰關(guān)系的表格,和從一個國家移動到另一個的G值。你也需要估算H值的方法。其
26、他的事情就 和例子中完全一樣了。當(dāng)你需要向開啟列表中添加新元素的時候,不需使用相鄰的格子,取而代之的是從表格中尋找相鄰的國家。類似的,你可以為一張確定的地形圖創(chuàng)建路徑點系統(tǒng),路徑點一般是路上,或者地牢通道的轉(zhuǎn)折點。作為游戲設(shè)計者,你可以預(yù)設(shè)這些路徑點。兩個路徑點被認(rèn)為是 相鄰的如果他們之間的直線上沒有障礙的話。在冒險棋的例子里,你可以保存這些相鄰信息在某個表格里,當(dāng)需要在開啟列表中添加元素的時候使用它。然后你就可 以記錄關(guān)聯(lián)的G值(可能使用兩點間的直線距離),H值(可以使用到目標(biāo)點的直線距離),其他都按原先的做就可以了。Amit Patel 寫了其他方法的摘要。另一個在非方形區(qū)域搜索RPG地圖
27、的例子,查看我的文章Two-Tiered A* Pathfinding。(譯者注:譯文: A*分層尋路)6. 一些速度方面的提示:當(dāng)你開發(fā)你自己的A*程序,或者改寫我的,你會發(fā)現(xiàn)尋路占據(jù)了大量的CPU時間,尤其是在大地圖上有大量對象在尋路的時候。如果你閱 讀過網(wǎng)上的其他材料,你會明白,即使是開發(fā)了星際爭霸或帝國時代的專家,這也無可奈何。如果你覺得尋路太過緩慢,這里有一些建議也許有效: * 使用更小的地圖或者更少的尋路者。 * 不要同時給多個對象尋路。取而代之的是把他們加入一個隊列,把尋路過程分散在幾個游戲周期中
28、。如果你的游戲以40周期每秒的速度運(yùn)行,沒人能察覺。但是當(dāng)大量尋路者計算自己路徑的時候,他們會發(fā)覺游戲速度突然變慢。 * 盡量使用更大的地圖網(wǎng)格。這降低了尋路中搜索的總網(wǎng)格數(shù)。如果你有志氣,你可以設(shè)計兩個或者更多尋路系統(tǒng)以便使用在不同場合,取決于路徑的長度。這也正是 專業(yè)人士的做法,用大的區(qū)域計算長的路徑,然后在接近目標(biāo)的時候切換到使用小格子/區(qū)域的精細(xì)尋路。如果你對這個觀點感興趣,查閱我的文章Two-Tiered A* Pathfinding。(譯者注:譯文 :A*分層尋路) * 使用路徑點系統(tǒng)計算長路徑,或者預(yù)先計算好
29、路徑并加入到游戲中。 * 預(yù)處理你的地圖,表明地圖中哪些區(qū)域是不可到達(dá)的。我把這些區(qū)域稱作“孤島”。事實上,他們可以是島嶼或其他被墻壁包圍等無法到達(dá)的任意區(qū)域。A*的下限 是,當(dāng)你告訴它要尋找通往那些區(qū)域的路徑時,它會搜索整個地圖,直到所有可到達(dá)的方格/節(jié)點都被通過開啟列表和關(guān)閉列表的計算。這會浪費(fèi)大量的CPU時 間。可以通過預(yù)先確定這些區(qū)域(比如通過flood-fill或類似的方法)來避免這種情況的發(fā)生,用某些種類的數(shù)組記錄這些信息,在開始尋路前檢查它。 * 在一個擁擠的類似迷宮的場合,把不能連通的節(jié)點看作死端。這些區(qū)域
30、可以在地圖編輯器中預(yù)先手動指定,或者如果你有雄心壯志,開發(fā)一個自動識別這些區(qū)域的算 法。給定死端的所有節(jié)點可以被賦予一個唯一的標(biāo)志數(shù)字。然后你就可以在尋路過程中安全的忽略所有死端,只有當(dāng)起點或者終點恰好在死端的某個節(jié)點的時候才需 要考慮它們。7. 維護(hù)開啟列表:這是A*尋路算法最重要的組成部分。每次你訪問開啟列表,你都需要尋找F值最低的方格。有幾種不同的方法實現(xiàn)這一點。你可以把路徑元素隨意 保存,當(dāng)需要尋找F值最低的元素的時候,遍歷開啟列表。這很簡單,但是太慢了,尤其是對長路徑來說。這可以通過維護(hù)一格排好序的列表來改善,每次尋找F值 最低的方格只需要選取列表的首元素。當(dāng)我自己實現(xiàn)的時候,這種方
31、法是我的首選。在小地圖。這種方法工作的很好,但它并不是最快的解決方案。更苛求速度的A*程序員使用叫做二叉堆的方法,這也是我在代碼中使用的方法。憑我的經(jīng)驗,這種 方法在大多數(shù)場合會快23倍,并且在長路經(jīng)上速度呈幾何級數(shù)提升(10倍以上速度)。如果你想了解更多關(guān)于二叉堆的內(nèi)容,查閱我的文章,Using Binary Heaps in A* Pathfinding。(譯者注:譯文:在A*尋路中使用二叉堆)另一個可能的瓶頸是你在多次尋路之間清除和保存你的數(shù)據(jù)結(jié)構(gòu)的方法。我個人更傾向把所有東西都存儲在數(shù)組里面。雖然節(jié)點可以以面向?qū)ο蟮娘L(fēng)格被動態(tài)的產(chǎn) 生,記錄和保存,我發(fā)現(xiàn)創(chuàng)建和刪除對象所增加的大量時間,
32、以及多余的管理層次減慢的整個過程的速度。但是,如果你使用數(shù)組,你需要在調(diào)用之間清理數(shù)據(jù)。這 中情形你想做的最后一件事就是在尋路調(diào)用之后花點時間把一切歸零,尤其是你的地圖很大的時候。我通過使用一個叫做whichList(x,y)的二維數(shù)組避免這種開銷,數(shù)組的每個元素表明了節(jié)點在開啟列表還是在關(guān)閉列表中。嘗試尋路之后,我沒有清 零這個數(shù)組。取而代之的是,我在新的尋路中重置onClosedList和onOpenList的數(shù)值,每次尋路兩個都+5或者類似其他數(shù)值。這種方法, 算法可以安全的跳過前面尋路留下的臟數(shù)據(jù)。我還在數(shù)組中儲存了諸如F,G和H的值。這樣一來,我只需簡單的重寫任何已經(jīng)存在的值而無需被
33、清除數(shù)組的操作干 擾。將數(shù)據(jù)存儲在多維數(shù)組中需要更多內(nèi)存,所以這里需要權(quán)衡利弊。最后,你應(yīng)該使用你最得心應(yīng)手的方法。8. Dijkstra的算法:盡管A*被認(rèn)為是通常最好的尋路算法(看前面的“題外話”),還是有一種另外的算法有它的可取之處-Dijkstra算法。 Dijkstra算法和A*本質(zhì)是相同的,只有一點不同,就是Dijkstra算法沒有啟發(fā)式(H值總是0)。由于沒有啟發(fā)式,它在各個方向上平均搜索。 正如你所預(yù)料,由于Dijkstra算法在找到目標(biāo)前通常會探索更大的區(qū)域,所以一般會比A*更慢一些。那么為什么要使用這種算法呢?因為有時候我們并不知道目標(biāo)的位置。比如說你有一個資源采集單位,需
34、要獲取某種類型的資源若干。它可能知道幾個資源區(qū)域,但 是它想去最近的那個。這種情況,Dijkstra算法就比A*更適合,因為我們不知道哪個更近。用A*,我們唯一的選擇是依次對每個目標(biāo)許路并計算距離, 然后選擇最近的路徑。我們尋找的目標(biāo)可能會有不計其數(shù)的位置,我們只想找其中最近的,而我們并不知道它在哪里,或者不知道哪個是最近的。進(jìn)一步的閱讀好,現(xiàn)在你對一些進(jìn)一步的觀點有了初步認(rèn)識。這時,我建議你研究我的源代碼。包里面包含兩個版本,一個是用C+寫的,另一個用Blitz Basic。順便說一句,兩個版本都注釋詳盡,容易閱讀,這里是鏈接。 * 例子代碼: A* Pa
35、thfinder (2D) Version 1.9如果你既不用C+也不用Blitz Basic,在C+版本里有兩個小的可執(zhí)行文件。Blitz Basic可以在從Blitz Basic網(wǎng)站免費(fèi)下載的Blitz Basic 3D(不是Blitz Plus)演示版上運(yùn)行。Ben ONeill提供一個聯(lián)機(jī)演示可以在這里找到。你也該看看以下的網(wǎng)頁。讀了這篇教程后,他們應(yīng)該變得容易理解多了。 * Amit的 A* 頁面:這是由Amit Patel制作,被廣泛引用的頁面,如果你沒有事先讀這篇文章,可能會有點難以理解。值得一看。尤其要看Amit關(guān)于這個問題的自己的看法。
36、160; * Smart Moves:智能尋路:Bryan Stout發(fā)表在G的這篇文章需要注冊才能閱讀。注冊是免費(fèi)的而且比起這篇文章和網(wǎng)站的其他資源,是非常物有所值的。Bryan用Delphi寫的程序幫助我學(xué)習(xí)A*,也是我的A*代碼的靈感之源。它還描述了A*的幾種變化。 * 地形分析: 這是一格高階,但是有趣的話題,Dave Pottinge撰寫,Ensemble Studios的專家。這家伙參與了帝國時代和君王時代的開發(fā)。別指望看懂這里所有的東西,但是這是篇有趣的文章也許會讓你產(chǎn)生自己的想法。它包含一些對 mip-mapping,
37、influence mapping以及其他一些高級AI/尋路觀點。對”flood filling”的討論使我有了我自己的“死端”和“孤島”的代碼的靈感,這些包含在我Blitz版本的代碼中。其他一些值得一看的網(wǎng)站: * aiGuru: Pathfinding * Game AI Resource: Pathfinding * GameD: Pathfinding我同樣高度推薦下面這幾本書, 里面有很多關(guān)于尋路和其他AI話題的文章。 它們也附帶了實例代碼的CD。這些書我都買了。另外,如果你通
38、過下面的鏈接購買了它們,我會從Amazon得到幾個美分。D星算法動態(tài)路網(wǎng),最短路徑算法 D*A* 在靜態(tài)路網(wǎng)中非常有效(very efficient for static worlds),但不適于在動態(tài)路網(wǎng),環(huán)境如權(quán)重等不斷變化的動態(tài)環(huán)境下。 D*是動態(tài)A*(D-Star,Dynamic A Star) 卡內(nèi)及梅隆機(jī)器人中心的Stentz在1994和1995年兩篇文章提出,主要用于機(jī)器人探路。是火星探測器采用的尋路算法。Optimal and Efficient Path Planning for Partially-Known Environments The Focussed D
39、* Algorithm for Real-Time Replanning 主要方法(這些完全是Drew在讀了上述資料和編制程序中的個人理解,不能保證完全正確,僅供參考):1.先用Dijstra算法從目標(biāo)節(jié)點G向起始節(jié)點搜索。儲存路網(wǎng)中目標(biāo)點到各個節(jié)點的最短路和該位置到目標(biāo)點的實際值h,k(k為所有變化h之中最小的 值,當(dāng)前為k=h。每個節(jié)點包含上一節(jié)點到目標(biāo)點的最短路信息1(2),2(5),5(4),4(7)。則1到4的最短路為1-2-5-4。原OPEN和CLOSE中節(jié)點信息保存。2.機(jī)器人沿最短路開始移動,在移動的下一節(jié)點沒有變化時,無需計算,利用上一步Dijstra計算出的最短路信息從出發(fā)
40、點向后追述即可,當(dāng)在Y點探測到 下一節(jié)點X狀態(tài)發(fā)生改變,如堵塞。機(jī)器人首先調(diào)整自己在當(dāng)前位置Y到目標(biāo)點G的實際值h(Y),h(Y)=X到Y(jié)的新權(quán)值c(X,Y)+X的原實際值 h(X).X為下一節(jié)點(到目標(biāo)點方向Y->X->G),Y是當(dāng)前點。k值取h值變化前后的最小。3.用A*或其它算法計算,這里假設(shè)用A*算法,遍歷Y的子節(jié)點,點放入CLOSE,調(diào)整Y的子節(jié)點a的h值,h(a)=h(Y)+Y到子節(jié)點a的權(quán)重C(Y,a),比較a點是否存在于OPEN和CLOSE中,方法如下:while()從OPEN表中取k值最小的節(jié)點Y;遍歷Y的子節(jié)點a,計算a的h值 h(a)=h(Y)+Y到子節(jié)點a的
41、權(quán)重C(Y,a) if(a in OPEN) 比較兩個a的h值 if( a的h值小于OPEN表a的h值 ) 更新OPEN表中a的h值;k值取最小的h值 有未受影響的最短路經(jīng)存在 break; &
42、#160; if(a in CLOSE) 比較兩個a的h值 /注意是同一個節(jié)點的兩個不同路徑的估價值 if( a的h值小于CLOSE表的h值 ) 更新CLOSE表中a的h值; k值取最小的h值;將a節(jié)點放入OPEN表 有未受影響的最短路經(jīng)存在 break;
43、60; if(a not in both) 將a插入OPEN表中;/還沒有排序放Y到CLOSE表;OPEN表比較k值大小進(jìn)行排序;機(jī)器人利用第一步Dijstra計算出的最短路信息從a點到目標(biāo)點的最短路經(jīng)進(jìn)行。D*算法在動態(tài)環(huán)境中尋路非常有效,向目標(biāo)點移動中,只檢查最短路徑上下一節(jié)點或臨近節(jié)點的變化情況,如機(jī)器人尋路等情況。對于距離遠(yuǎn)的最短路徑上發(fā)生的變化,則感覺不太適用。 上圖是Drew在4000個節(jié)點的隨機(jī)路網(wǎng)上做的分析演 示,細(xì)黑線為第一次計算出
44、的最短路,紅點部分為路徑上發(fā)生變化的堵塞點,當(dāng)機(jī)器人位于982點時,檢測到前面發(fā)生路段堵塞,在該點重新根據(jù)新的信息計算路 徑,可以看到圓圈點為重新計算遍歷過的點,僅僅計算了很少得點就找到了最短路,說明計算非常有效,迅速。綠線為計算出的繞開堵塞部分的新的最短路徑。 · state:將空間(地圖)分隔成若干個節(jié)點,每個節(jié)點記著一個state,它有三個狀態(tài)NEW,OPEN和CLOSED,等會講tag時再對這幾個狀態(tài)做說明· directional arc:連接兩個state之間的directional arc,也就是通過這個directional arc,可以從一個state到達(dá)
45、另一個state· backpointer:除去目標(biāo)state外的任意state X都有一個backpointer,使之能到達(dá)另一個state Y,既b(X) = Y;D*算法也正是使用這一系列的backpointers來描述到達(dá)目的點的路徑· arc cost:state Y通過directional arc到達(dá)state X的所需的成本,記著c(X,Y);這個概念類似于權(quán)值。如果c(X,Y)無法定義,則說明state Y沒有指向X的 arc;當(dāng)c(X,Y)和c(Y,X)均能定義,則說明X和Y在空間上是相鄰的· OPEN list:D*算法里也有一個OPEN列表
46、來記錄states(這個與A*類似);它用于在arc cost函數(shù)變化時傳遞信息和計算state的路徑價值· tag:每個state都有一個標(biāo)記(前面講state時提到的狀態(tài)),當(dāng)state為NEW時,表明該state從未在OPEN列表中;如果state為OPEN,該state正在OPEN列表中;而當(dāng)state為CLOSED時,則說明該state不會在OPEN列表中存在· path cost:D*通過h(G, X)函數(shù)來估計任意點X到目標(biāo)點G的arc cost總和,這個Heuristics函數(shù)與A*算法里的h函數(shù)功能相似· optimal cost:在適當(dāng)?shù)臈l件下,該隱式函數(shù)能估計出從任意點X到目標(biāo)點G的最佳路徑· key function:當(dāng)X在OPEN列表中,并且所有點都未變動并通過h(G, X)進(jìn)行的估計的前提下,k(G, X)等于h(G, X)的最小值,根據(jù)該函數(shù)值的不同,可以將X state分
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 上海市縣(2024年-2025年小學(xué)五年級語文)統(tǒng)編版階段練習(xí)(下學(xué)期)試卷及答案
- 四年級數(shù)學(xué)(除數(shù)是兩位數(shù))計算題專項練習(xí)及答案
- 高三地理第一輪教案-中國地理
- 山西省大同市2024-2025學(xué)年上學(xué)期期中教學(xué)質(zhì)量監(jiān)測八年級物理(含答案)
- 低音吉他產(chǎn)業(yè)運(yùn)行及前景預(yù)測報告
- 頭發(fā)護(hù)理咨詢行業(yè)市場調(diào)研分析報告
- 寵物用除虱梳產(chǎn)業(yè)規(guī)劃專項研究報告
- 勺形鏟餐具市場需求與消費(fèi)特點分析
- 人教版英語八年級下冊 Unit 1 Section A (1a-2d)隨堂練習(xí)
- 人教版八年級英語上冊Unit 3 Section A 測試卷
- 《應(yīng)收賬款存在的問題及對策-以海爾公司為例(論文)9500字》
- 跟管鉆孔法施工方案
- 重慶市普通中小學(xué)課程計劃
- 酒店項目投資測算模型
- 《中國民間故事》整本書閱讀交流展示課ppt課件(完美版) 小學(xué)語文五年級必讀書目快樂讀書吧
- 北師大四上數(shù)學(xué)期中復(fù)習(xí)(個人整理)課件
- 青島版三年級上冊數(shù)學(xué) 分?jǐn)?shù)的初步認(rèn)識 課件(共16張ppt)
- 一、二星級綠色建筑評價標(biāo)識申報書
- 四川省地震災(zāi)區(qū)重大地質(zhì)災(zāi)害治理工程資料全套表格
- 我國油菜生產(chǎn)機(jī)械化技術(shù)(-119)
- 2022年廣西南寧市八年級上學(xué)期期末語文試卷
評論
0/150
提交評論