unity中尋路方案的討論

A * 算法

基本的原理

詳解
全方位分析
c++實現

A* 算法不是最短路徑算法,它找到的路徑並不是最短的,它的目標是以最快的速度找到通往目的地的路,它的時間複雜度爲O(NlogN)
A* 算法使用的是一種局部最優的策略,它的下一步的選擇點,是距離目的地最短的點。以二維數組爲例,s點, 取出它周圍的8個點(可行走點),然後加入到open_list,然後對隊列排序,找到距離最近的點,這個點就是下一個點k, 並將k加入到close_list,然後再取k的周圍的沒有標記的點,加入到未標記隊列中,再對隊列排序,直到到達目的地。
它只關注當前最優 的,可能會走彎路。

在排序時的依據,就是點的總代價
F = G + H
F理解爲通過這個點的總代價,代價越低,這個就當然更有可能在最短路徑上。 G是從起點到這個點的代價, H是從這個點到終點的代價
G的計算,可以通過它的父節點的G來計算
H的計算,只能用估算,有多種算法,可以使用曼哈頓距離, 值計算當前方格橫向或縱向移動到達目的所經過的方格數,忽略對角移動,然後總數乘以10 ,並且在統計過程中,忽略障礙物, 是一種估計值。

從open_list中選擇F值最小的節點,然後把它從open_list中移除,加入到close_list 。然後檢查所有與他相鄰的方格,忽略close_list中的,不可行走的, 如果不在open_list中,就把當前方格設置爲它的父親,並記錄該方格的F,G, H值。如果鄰近節點已經在open_list中, 就要檢查經由當前節點到達它那裏是否更好,以G來爲參考,如果G更小,說明從當前節點過去是更好的路徑,就把它的父節點設置爲當前方格,並重新計算它的G和F。
這種父子關係,最後用來連接路徑。
注意,每次循環查找到下一個路徑點,並不一定就是最終的路徑點,因爲,後面會對節點進行優化,修改父子關係。

直到, 終點加入到open_lsit中,此時路徑已經找到了,或者查找終點失敗, 並且open_list爲空,此時沒有路徑。
從終點開始,每個方格沿着父節點移動直到起點,就是查找的路徑。

A * 算法優化

在地圖很大時, 使用A星算法,尋路頻率很高,普通的A星算法,消耗大量的CPU計算。
1.對排序算法優化,當距離很遠, 未標記隊列會越來越大, 排序的時間也會越來越長。由於在插入新的點前,隊列是有序的,考慮使用插入排序,而不是每次都使用快排,可以用二分查找,插入。

尋路網格構建

A* 算法只是算法,需要配套的模塊來支持, 最重要的就是尋路網格的構建,還有動態障礙物,地圖和地形支持,再配上尋路算法,纔會形成最終的地圖和尋路。

  1. 最簡單的就是二維數組構建的方形網格
    將地圖與二維數組對應,進行地圖的切割。這樣就用A星的尋路在數組中結果對應到地圖上。但是當地圖很大時, 數組如果太小,無法實現細膩的碰撞體;如果數組太大, 就造成內存的消耗。這放方式在2D遊戲,或者是橫版遊戲時,還是可以使用,畢竟比較單一。

  2. 多邊形網格的構建-NavMesh。
    能夠大大改善尋路的效率。
    它的本質就是三角形網格生成算法+多邊形之間的合批和裁切算法+A*
    三角形生成:切耳算法
    網格構建完畢後,需要將A* 與網格數據結合
    A星的特點,必須由鄰近的節點可獲取,並且鄰近的節點與目的地的可以有距離比較。
    在平面三角形網格中,要從一個點到另一個點,則可以使用三角形的鄰近三角形來計算路徑,與目的地的距離可以用點與點之間的距離來計算。
    知道了路徑上需要經過哪些三角形,那麼問題來了, 行走的路徑是根據點來判斷的,三角形怎麼定點,三角形的大小不一,如果定位到中心點,行走就很怪異。所以引入了拐點路徑算法來優化尋路後的路徑。

Flow Field PathFinding 算法

參考
v社提出的場尋路算法 ,針對RTS遊戲,多個戰鬥單位
基於Dijkstra算法
簡單介紹

基本方案介紹:

A * Pathfinding Project

下載
也可以從Assetstore下載直接導入到工程,是在A* 算法基礎上進行改善的尋路插件
簡單教程
有人說它的碰撞有問題 ,待考證
基於網格的是免費的。
自動生成navmesh的工具,只有pro版本有。
不過可以使用其他方法生成navmesh, 然後再利用它的尋路系統,白嫖

路點尋路

預先設置好路徑點座標幾何,然後對象按照規定的座標幾何運動。
用於塔防怪物行進路徑,魚羣遊動路徑,AI的巡邏路徑等,實現起來也最簡單方便,不需要計算量。
但是在MMO中,由於任務太多,如果預先設置,工作量太大了,而且每次調整都是很大的工作量。

Unity自帶的Navigation

前面說了,它是將地圖轉換爲三角形網格的集合,網格和網格之間構成連通關係用於尋路。
1.Navmesh尋路快,但不夠精確。
2. 不開源,導致遊戲服務器無法使用,無法和客戶端保持一致的導航尋路邏輯。
3.有人說,在多人尋路時,存在擠壓問題。說navigation沒有把其他人當作 障礙物,遇到其他人會因爲碰撞而減速,變方向。?
4.不適合在幀同步中使用,因爲需要確保每個客戶端的計算結構都一致。
5.不能動態加載Navmesh, 不能動態的替換和修改navmesh,比如動態的遮擋。

有的項目使用A* pathfinding pro(收費) + Navmesh
1.主體尋路方案使用A * 插件中的傳統的網格形式,並進行深度修改擴展。
2.使用navmesh系統作爲尋路過程中的碰撞系統,它自帶碰撞算法,使用rvo算法,用來實現局部的碰撞規避。
參考uwa

Recast Navigation

客戶端和服務器都可以使用 ,自帶生成navmesh的方法,而且是開源的,可以學習其中的原理
尋路的核心算法,也還是A*算法。

討論

在以前的moba中,使用A* Pathfinding pro, 碰撞是自己實現的。王者榮耀好像也是用的這個插件。

MMO中使用Recast Navigation, 用c++編寫,可以給服務器使用來尋路,它是untiy的自帶navigation的前生。
不過Recast Navigation本身也有一些限制,在後續的文章中會簡單介紹。
還可以編譯成庫,給客戶端使用。
它提供的工具可以用來生成navmesh, 或者使用untiy來bake出navmesh,然後導出爲recast識別的obj, 在reecast中再生成navmesh。

在橫版遊戲中,由於地圖簡單,就是長方形,直接用一個網格生成工具,根據layer,來生成二維數組,標記處碰撞物體,然後保存爲二進制文件;給服務器來判斷,並且可以動態的修改,比如一些機關,空氣牆。客戶端本地將二維數組序列化到地圖中,這樣可以動態判斷,某個座標點是否是可行走的,用來做隨機掉落點的計算。

當然可以自己實現一套,實現A* 算法,再結合自己的項目特性。

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