Unity尋路插件(A* Pathfinding)進階教程十四:多agent類型 本系列的教程文章基於 A*Pathfinding Project 4.2.8的官網教程翻譯,每一章節的原文地址都會在教程最下方給出。這篇會講怎麼處理不同類型的agent,比如尺寸方面的。如果你的agents的尺寸不同,它們通常不會找到相同的路徑。但是幸運的是,我們有辦法解決。最簡單的方法就是創建多個graphs,每種類型對應一個特定的graph。但是如果你有很多個不同類型的agent,那麼你就需要創建非常多的graphs,這樣不但會快速消耗內存,還會增加scanning的時間。在Seeker組件上,可以設置seeker使用哪個graph。 示例 假如我們有2個agents: 在AstarPath的面板上,我們可以創建兩個不同的graphs,唯一的區別就是 character radius不一樣。(其他的參數其實也可以不一樣,根據你的需求決定)在這個示例里,我們使用了recast類型,但其實其他的類型也是一樣簡單的。 scan之後,我們會得到一個結果如下圖所示。小的agents是藍色的,大的是紫色的。 在Seeker組件,我們可以選擇使用哪一個graph。 那麼現在每一個agent都使用了適合他們自己大小的graph了。 00:17 grid graph的其他方式 在grid的graph上,可以使用其他方式來替代。讓graph根據障礙物不同的距離生成不同的tag,這隻適用於single graph。還有一種方法非常高效,但是不好的是計算的代價比較大。對於路徑請求,可以提供一個ITraversalProvider對象,用來確定哪些節點不應該遍歷。這在之前的文章里有提到過。放牛的星星:Unity尋路插件(A* Pathfinding)進階教程九:基於turn-based的遊戲實戰?zhuanlan.zhihu.com使用這個的話,我們可以添加自定義代碼,而不僅僅是檢查它是否可以遍歷。當然我們還可以檢查它周圍的所有節點,例如一個3X3或者5X5平方的範圍。(默認是1X1)下面的圖片展示了使用3X3的情況。請注意,即使某個節點是可以通行的它也不會過去,因為它會檢查周圍3X3的範圍。 ITraversalProvider的方法主要優點就是,它會處理所有導致節點不可遍歷的事情。比如,你可以使用不同的標記來限制代理的移動。但是,如果你使用的是多個graph,不同的agent仍然是能夠根據tag標識到達一個區域,即使該區域不能通行,當然前提是它的size要足夠大。而這種方法它就沒有辦法到達,因為除了檢查必要可通行的節點,它還檢查每個節點周圍NXN的區域。ITraversalProvider的代碼 大概可以這樣寫:class GridShapeTraversalProvider : ITraversalProvider { Int2[] shape; public static GridShapeTraversalProvider SquareShape (int width) { if ((width % 2) != 1) throw new System.ArgumentException("only odd widths are supported"); var shape = new GridShapeTraversalProvider(); shape.shape = new Int2[width*width]; // Create an array containing all integer points within a width*width square int i = 0; for (int x = -width/2; x <= width/2; x++) { for (int z = -width/2; z <= width/2; z++) { shape.shape[i] = new Int2(x, z); i++; } } return shape; } public bool CanTraverse (Path path, GraphNode node) { GridNodeBase gridNode = node as GridNodeBase; // Dont do anything special for non-grid nodes if (gridNode == null) return DefaultITraversalProvider.CanTraverse(path, node); int x0 = gridNode.XCoordinateInGrid; int z0 = gridNode.ZCoordinateInGrid; var grid = gridNode.Graph as GridGraph; // Iterate through all the nodes in the shape around the current node // and check if those nodes are also traversable. for (int i = 0; i < shape.Length; i++) { var inShapeNode = grid.GetNode(x0 + shape[i].x, z0 + shape[i].y); if (inShapeNode == null || !DefaultITraversalProvider.CanTraverse(path, inShapeNode)) return false; } return true; } public uint GetTraversalCost (Path path, GraphNode node) { // Use the default traversal cost. // Optionally this could be modified to e.g taking the average of the costs inside the shape. return DefaultITraversalProvider.GetTraversalCost(path, node); } } 記住這個擴展只能在grid使用,不能再layered grid graphs上使用。 那麼使用的方式如下:ABPath path = ABPath.Construct(currentPosition, destination, null); path.traversalProvider = GridShapeTraversalProvider.SquareShape(3); // If you are writing your own movement script seeker.StartPath(path); // If you are using an existing movement script (you may also want to set ai.canSearch to false) // ai.SetPath(path); 注意,如果使用這兩種grid的方法,還有一個弊端。當你要尋找的目標點完全無法到達的時候,那麼尋路就會失敗,而不是像通常一樣找到一個離它最近的點。你可以在計算路徑前使用CompuatePartial欄位為true來解決某些情況下產生的問題。 path.calculatePartial = true; 根據提供的ITraversalProvider,只要目標節點是一個可遍歷的節點,它就能保證獲得一個最近的節點。原文地址:Documentation?arongranberg.com 推薦閱讀: 相关文章 {{#data}} {{title}} {{/data}}