本系列的教程文章基於 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上,可以使用其他方式來替代。讓graph根據障礙物不同的距離生成不同的tag,這隻適用於single graph。
還有一種方法非常高效,但是不好的是計算的代價比較大。對於路徑請求,可以提供一個ITraversalProvider對象,用來確定哪些節點不應該遍歷。這在之前的文章里有提到過。
使用這個的話,我們可以添加自定義代碼,而不僅僅是檢查它是否可以遍歷。當然我們還可以檢查它周圍的所有節點,例如一個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,只要目標節點是一個可遍歷的節點,它就能保證獲得一個最近的節點。
原文地址: