Unity寻路插件(A* Pathfinding)进阶教程十三:访问graph数据
本系列的教程文章基于 A*Pathfinding Project 4.2.8的官网教程翻译,每一章节的原文地址都会在教程最下方给出。所有graph的数据都是可以访问的。有很多时候我们都希望能够得到graph数据,比如当一个API想把一个GraphNode当做一个参数来对待的时候,你就需要去找到它们。另一些情况则可能是你希望去改变其中的一些数据来适配你的游戏。比如你可能自定义了一个tilemap的生成器,然后你想把这些数据传递给graph。
可以参考之前的章节:如果想了解怎样找到一个点的最近Node,可以参考访问Graph
所有的graph都存在PathFinding.AstarData类中。它包含了一个存储了所有graph的数组。有一大堆快捷的方式可以找到graph。这里介绍最快的一种,也是插件本身提供的快捷接口。每一种内置的graph都有一个字段来指向它们。
GridGraph gridGraph = AstarPath.active.data.gridGraph;
PointGraph pointGraph = AstarPath.active.data.pointGraph;
NavMeshGraph navmeshGraph = AstarPath.active.data.navmesh;
RecastGraph recastGraph = AstarPath.active.data.recastGraph;
LayerGridGraph layerGridGraph = AstarPath.active.data.layerGridGraph;
NavGraph[] allGraphs = AstarPath.active.data.graphs;
// You can set the name of a graph in the graph inspector
var graph = AstarPath.active.data.FindGraph(g => g.name == "My Custom Graph Name");
在Graph中获取节点
不同的graph存储节点的方式也不同。比如grid类型的会把所有的节点存储为一个巨大的数组,但是可以使用index快速访问gird的index。recast类型则是把所有节点存储在不同的tile中。
通用的火的节点比较高效的方法就是使用每个graph自己提供的GetNodes方法。它提供了一个回调函数来执行每一个Node。之所以使用回调而不是迭代器(iterator)的理由是因为在巨大的处理graphs的不同行为时候,回调的性能比迭代器要高。
var gg = AstarPath.active.data.gridGraph;
gg.GetNodes(node => {
// Here is a node
Debug.Log("I found a node at position " + (Vector3)node.position);
});
警告:不要更新node的数据。因为它可能会干扰异步的路径查找结果。安全的更新节点数据的方法是使用内部的安全回调,比如:AstarPath.AddWorkItem
可以查看上面提到的 进阶教程六GridGraph
GridGraph使用一个巨大的数组存储的,他们会根据坐标计算出一个Index索引,所以访问它们的时候非常简单。当然也有其他方便的方式访问:
var gg = AstarPath.active.data.gridGraph;
int x = 5;
int z = 8;
GridNodeBase node = gg.GetNode(x, z);
有一些时候,你可能想在运行时改变一个gridGraph的大小(size)。那么你可以修改unclampedSize字段,这是Unity中的单位大小。也可以用SetDimensions方法。在你改变了Width或者Depth之后,记得调用AstarPath.Scan来重新计算。
var gg = AstarPath.active.data.gridGraph;
var width = 80;
var depth = 60;
var nodeSize = 1.0f;
gg.SetDimensions(width, depth, nodeSize);
// Recalculate the graph
AstarPath.active.Scan();
当然也有不用重新计算grid的方法,那就是RelocateNodes。这个方法在其他的graphs里也适用,但是需要你自己提供必要的矩阵。
Layered Grid Graph
Layered Grid Graph的工作原理和gird Graph像。但是因为它会存储不同的layer,所以还需要指定一个Layer的Index。
var gg = AstarPath.active.data.layerGridGraph;
int x = 5;
int z = 8;
int layer = 0;
GridNodeBase node = gg.GetNode(x, z, layer);
NavmeshGraph/RecastGraph
Recast graphs把节点分在不同的tiles里面。但各个存储快的存储方式则和grid是一样的。在每一个tile里面,数据的排布方式没有固定的顺序。但是所有的节点也被添加到一个轴对齐的包围盒树 AABB树种,以便高效的查找距离某一个点最近的node。Navmesh graphs的数据组织和 recast一样,只不过它只有一个tile而已。
var graph = AstarPath.active.data.recastGraph;
int tileX = 5;
int tileZ = 8;
NavmeshTile tile = graph.GetTile(tileX, tileZ);
for (int i = 0; i < tile.nodes.Length; i++) {
// ...
}
// or you can access the nodes like this:
tile.GetNodes(node => {
// ...
});
PointGraph
PointGraph也是简单的把node存成了一个无序的数组。
PointGraph还包含了一个为GameObject创建的字段(如果需要的话),你可以用来做你需要做的事情。
var node = AstarPath.active.GetNearest(transform.position).node;
var pointNode = node as PointNode;
if (pointNode != null) {
Debug.Log(&#34;That node was created from the GameObject named &#34; + pointNode.gameObject.name);
} else {
Debug.Log(&#34;That node is not a PointNode&#34;);
}
你也可以在运行时添加一个节点:
AstarPath.active.AddWorkItem(new AstarWorkItem(ctx => {
var graph = AstarPath.active.data.pointGraph;
// Add 2 nodes and connect them
var node1 = graph.AddNode((Int3)transform.position);
var node2 = graph.AddNode((Int3)(transform.position + Vector3.right));
var cost = (uint)(node2.position - node1.position).costMagnitude;
node1.AddConnection(node2, cost);
node2.AddConnection(node1, cost);
}));
原文地址:
页:
[1]