使用A* Pathfinding Project的一些心得


最近在游戲開發中要做尋路。首選果斷就是Unity3D自帶的尋路啦。方便穩定,基本功能都能滿足。我們的需求也不復雜,就是一個英雄在不同的地圖中探索。但是介於一個比較惡心的問題,果斷放棄了它。所以,說A* Pathfinding Project之前,讓我先吐槽幾百字……

 
這個問題就是NavMesh不能動態地加載。Unity3D中每一個場景的NavMesh,如果有的話,都會對應一個名叫NavMesh.asset的文件。一一對應。假如你使用Resources.Load()方法載入它,會發現它其實就是一個NavMesh類的實例。好方便啊~~。但是Unity3D卻沒有提供任何方法動態替換一個場景的NavMesh。NavMesh類都是靜態方法哦~。你就是載入進來,也拿它沒轍,哦吼吼~。那好吧,接受這個殘酷的現實。但哥不嫌麻煩,咱每一張地圖都建一個場景,對應一個NavMesh,可以了吧?理論上可以。但實際不行。介於場景眾多,你在操作它們的時候(移動、重命名等等),你不知什么時候,場景和它的NavMesh的關聯關系就會丟失。總之,再次給Unity3D的做了一半的功能跪了。
 
通過百度、谷歌,以及各種機緣巧合,知道了有A* Pathfinding Project這個尋路插件。看它高大上的官網( http://arongranberg.com/astar/),介紹的各種功能也是很強大的。A*,NavMesh和好多其它種哥也不懂的尋路算法都實現。 而且可以Save和Load預先做好的NavMesh和設置。於是哥決定嘗試一下……
 
A* Pathfinding Project
 
具體的使用,這里就不詳細說了。看它自帶的ExampleScenes以及官方教程( http://arongranberg.com/astar/docs/index.php)就可以了。下面說一些遇到的坑,希望對遇到的朋友有幫助。
 
1.如果你想要使用代碼來Scan,AstarPath.active.Scan()或者ScanLoop()是不靠譜的。它們只有在AstarPath這個組件被選中時才管用。建議使用AstarPathEditor.MenuScan()。這個是位於Edit菜單內的功能選項。是可以在編輯器內調用的。
 
2.建議使用RecastGraph替代NavMeshGraph。兩者尋路效果上沒有太大差別,只是NavMesh的生成方式不一樣。NavMeshGraph需要你手動指定一個Mesh。而RecastGraph是根據圖層,和擺在場景里的Mesh生成的NavMesh。甚至可以在運行時生成。相比指定一個Mesh要靈活多了。而且NavMeshGraph的UI代碼有問題,不能拖拽,必須從整個工程里面選。。。
 
3.AIPath這個很常用的腳本是有BUG的。雖然作者自己也說了吧。但沒想到問題那么明顯。作者為了達到最大程度地兼容,讓AIPath在GameObject上,依次去找CharacterController,Rigidbody,最后是Transform,來控制移動。如果使用Rigidbody的話,會使用AddForce()方法移動。但是,卻沒有判斷isKinematic這個屬性。如果為true,AddForce()肯定沒用啊。所以,自己加上個判斷唄……。
 
 1     public virtual void Update () {
 2         
 3         if (!canMove) { return; }
 4         
 5         Vector3 dir = CalculateVelocity (GetFeetPosition());
 6         //Rotate towards targetDirection (filled in by CalculateVelocity)
 7         RotateTowards (targetDirection);
 8     
 9         if (rvoController != null) {
10             rvoController.Move (dir);
11         } else
12         if (navController != null) {
13 #if FALSE
14             navController.SimpleMove (GetFeetPosition(),dir);
15 #endif
16         } else if (controller != null) {
17             controller.SimpleMove (dir);
18         } else if (rigid != null && !rigid.isKinematic) {
19             rigid.AddForce (dir);
20         } else {
21             transform.Translate (dir*Time.deltaTime, Space.World);
22         }
23     }
 
4.目前(3.5.1版本)A* Pathfinding Project還不支持躲避(Local Avoidance)。在之前版本,躲避是使用RVO這個插件實現的。但貌似由於版權問題,RVO被從A* Pathfinding Project中剝離了。如果非要實現躲避或動態阻擋這類功能,可以使用NavmeshCut這個組件。它只支持RecastGraph。原理就是實時地更新NavMesh,從中挖一個洞。要實現這個效果,場景中還必須掛一個TileHandlerHelper的組件。它會定時更新NavMesh。不過,如果阻擋物過多,或者更新頻率過於頻繁,肯定是不靠譜的。畢竟要修改Mesh也是有一定開銷的。那建議就選用別的尋路插件咯……。
 
5.另外,TileHandlerHelper會提前對graph進行判空檢查。假如,你的RecastGraph是運行時加載的,那這里肯定會報空指針。這是因為在AstarData類的DeserializeGraphsPart()方法里,對數據反序列化后,沒有更新AstarData.recastGraph這個字段。在DeserializeGraphsPart()最后手動調用一下UpdateShorcuts()就好了。
 1         public void DeserializeGraphsPart (Pathfinding.Serialization.AstarSerializer sr) {
 2             ClearGraphs ();
 3             graphs = sr.DeserializeGraphs ();
 4             if ( graphs != null ) for ( int i = 0; i<graphs.Length;i++ ) if ( graphs[i] != null ) graphs[i].graphIndex = (uint)i;
 5             
 6             userConnections = sr.DeserializeUserConnections();
 7             //sr.DeserializeNodes();
 8             sr.DeserializeExtraInfo();
 9             sr.PostDeserialization();
10 
11             UpdateShortcuts();
12         }

 

 
不論怎樣,作為一個第三方的尋路插件,A* Pathfinding Project功能已經很給力了,而且貌似還是一個人搞的(orz...)。所以有點小BUG也無可厚非了,就當鍛煉自己Debug的能力了。最后,還是給A* Pathfinding Project點32個贊~~ 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM