本系列的教程文章基于 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,只要目标节点是一个可遍历的节点,它就能保证获得一个最近的节点。
原文地址: