游戏中常用的寻路算法的分享(4)处理移动中的障碍物
一個尋路算法會計算出一條繞過靜止障礙物的路徑,但如果障礙物會移動呢?當一個單位移動到達某特定點時,原來的障礙物可能不在那點了,或者在那點上出現了新的障礙物。如果路線可以繞過典型的障礙物,那么只要使用單獨的避障算法來配合你的尋路算法。尋路算法會尋找到期望的路徑,并且在沿著路徑的同時繞過障礙物。但是如果障礙物可以移動,進而導致路徑不停地發生顯著改變,就應考慮使用尋路算法來避障。
重新計算路徑
我們希望游戲世界隨著時間改變。一條一段時間之前發現的路徑,可能不再是現在的最優路徑。用新的信息更新舊路徑是值得的。下面列出的是一些用來判斷決定是否需要重新計算路徑的標準:
每N步一次:這樣保證用來計算路徑的信息不會舊于N步。
當額外的CPU時間可用時:這樣可以實現路徑質量的動態調整。即使使用了更多的游戲單位,或者是在一臺較慢的電腦上運行游戲,每個游戲單位的CPU使用率都可以降低。
當游戲單位轉彎或者通過一個關鍵路徑點的時候。
當游戲單位附近的世界發生改變的時候。
重新計算路線的主要缺點在于有很多路徑信息被丟棄了。例如,如果路徑長100步,并且每十步進行一次重新計算,那么路徑的總步數是100+90+80+70+60+50+40+30+20+10 = 550。對于一個長M步的路徑,總共大概進行了M^2步計算。因此,如果你想要得到很多條長路徑,重新計算路線并不是一個好主意。重復使用路線信息,而非丟棄,這樣會是更好的辦法。
路徑剪接
當一條路徑需要被重新計算時,意味著世界正在改變。給定一個變化中的世界,地圖上的鄰近部分比遠處的部分更好了解。我們可以遵循一個局部修正策略:找到附近的一條好路徑,并且假定較遠的路徑直到我們靠近它了才需要重新計算。我們可以僅僅重新計算路徑的前M步,而不是整條路徑:
設p[1]..p[N] 是路徑剩余部分(N步)
計算一條從p[1]到p[M]新路徑
剪接新路徑到舊路徑中,通過移除p[1]..p[M]然后插入新路徑到這些空位置上。
?
因為p[1]和p[M]相距不到M步,所以新路線不太可能長。不幸的是,像新路徑又長又不是非常好的情況,也有可能發生。上圖展示了這樣一個情況。原始的紅色路徑是1-2-3-4,棕色區域是障礙。如果我們到達2然后發現從2到3的路徑被阻擋了,路徑剪接會用綠色的路徑2-5-3來替換2-3,導致這個單位循著路徑1-2-5-3-4移動。我們可以看到這并不是一個好的路徑,藍色路徑1-2-5-4是更好的選擇。
不好的路徑經??梢酝ㄟ^計算新路徑的長度來判斷。如果它明顯比M長,賣手機游戲平臺它就可能是不好的路徑。一個簡單的解決方法,給尋路算法添加一個上限(最大路徑長度)。如果找不到一條短的路徑,這個算法返回一個錯誤代碼,在這種情況下,使用重新計算路線而不是路線剪接來得到一條像1-2-5-4這樣的路徑。
對于沒有涉及到這類情況的例子,對于一條N步的路徑,路線剪接會計算2N到3N路徑步數,取決于一條新路徑進行剪接插入的頻繁程度。這是一個相對低的代價,使得算法能對世界的改變作出反應。意想不到的是,這個花費的代價大小取決于M,也就是進行剪接的路徑步數。M控制一個反饋和路徑質量的平衡,而不是CPU時間的影響。如果M的值較大,單位的移動將不會快速地對地圖的改變作出反饋。如果M太小,被剪接的路徑可能太短,以至于不能得到可以繞過障礙的替換路徑:更不優的路徑(例如1-2-5-3-4)可能會被找到,嘗試M的不同取值和不同的剪接標準(例如每隔3/4 M步),來看看怎樣做最適合你的地圖。
路徑剪接比重新計算路徑明顯地快了許多,但它對于路徑的重大改變并不能很好地應對。不過很多這種情況可以容易地發現,并直接使用重新計算路徑來代替路徑剪接。它同樣有幾個可以調整的變量,比如M和進行新路徑的尋找的時間,所以它可以被調整為適合不同的情況(即使是在運行的時候)。但是路徑剪接并不能處理游戲單位需要確定位置進而來互相穿過的情況。
監視地圖的改變
選擇重新計算全部或部分路徑在特定的時間間隔,是對地圖的改變來觸發重新計算。地圖可以分成不同的區域,每個游戲單位可以在特定的區域表現出興趣。(所有包括部分路徑的區域都可能是感興趣的,或者僅僅是鄰近的包含部分路徑的區域)無論障礙進入或離開某個區域,那個區域就標記為已經改變,然后所有對那個區域感興趣的游戲單位都會被通知,所以路徑可以在考慮障礙發生變化這一前提下被重新計算。
這一技術有很多可能的變化。例如,我們可以僅僅在特定的時間間隔通知游戲單位而不是立即通知。并且多次改變可以被組合成一次通知,所以不再需要過多的進行重新計算路徑。另一個變化是讓游戲單位來查詢地區的狀態,而不是讓地區來通知游戲單位。
監視地圖的改變,避免了游戲單位在障礙物沒有發生變化的時候進行重新計算,因此當你有很大地區不會經常發生改變的時候,可以考慮使用這種方法。
預測障礙物移動
如果障礙物的移動可以被預測,那就可以在進行尋路時把未來的障礙物位置納入考慮。像A*這類算法有一個代價函數,來決定通過地圖上某點的困難程度。A*可以被修改成實時更新到達一點所需要的時間(由當前的路徑長度決定),這個時間也可以被傳入代價函數中。代價函數就可以把時間納入考慮,然后就可以使用在那個時刻的障礙物預測位置,來決定那個地圖位置是否無法通過。但是這個修改并不完美,因為它不會考慮在某個點等待障礙物離開路徑的可能性,另外A*并不是設計用來區分相同路線上的路徑,而是時間不同的點。
總結
以上是生活随笔為你收集整理的游戏中常用的寻路算法的分享(4)处理移动中的障碍物的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 依赖注入 这样的坑游戏编程要谨慎
- 下一篇: 一个菜鸟程序员的游戏开发心得