A* Pathfinding Project  4.1.6
The A* Pathfinding Project for Unity 3D
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Events Macros Groups Pages
Accessing graph data

How to access graphs and nodes.

All data in the graphs can be accessed. There are for example many cases where the API expects a GraphNode as a parameter so you need to be able to find those. And there can be other cases where you need to extensively modify the graph data to suit your game. For example you might have your own custom made tilemap generator and you need to pass that data to the grid graph.

Finding Nodes close to Positions

// Find the closest node to this GameObject's position
GraphNode node = AstarPath.active.GetNearest(transform.position).node;
if (node.Walkable) {
// Yay, the node is walkable, we can place a tower here or something
}
Note
Also check out the page on updating graphs during runtime: Graph Updates during Runtime.

There are also cases where you want to get only certain nodes, such as "What is the closest *Walkable* node to this position?". This can be accomplished using the Pathfinding.NNConstraint. For this case the Default NNConstraint (it is called default, because it is used for path calls if nothing else is specified)

GraphNode node = AstarPath.active.GetNearest(transform.position, NNConstraint.Default).node;

You can also create custom constraints:

var constraint = NNConstraint.None;
// Constrain the search to walkable nodes only
constraint.constrainWalkability = true;
constraint.walkable = true;
// Constrain the search to only nodes with tag 3 or tag 5
// The 'tags' field is a bitmask
constraint.constrainTags = true;
constraint.tags = (1 << 3) | (1 << 5);
var info = AstarPath.active.GetNearest(transform.position, constraint);
var node = info.node;
var closestPoint = info.position;

The search range of these constraints is not unlimited, but quite large. The maximum distance can be set in A* Inspector -> Settings -> Max Nearest Node Distance or AstarPath.maxNearestNodeDistance. If the closest node is further away than the 'Max Nearest Node Distance' then the GetNearest method will return a null node.

See Also
Pathfinding.NNConstraint

Closest Point on Nodes

You may have noticed above that to get the node from the GetNearest call we had to access the node field. The GetNearest method returns an NNInfo struct which contains two fields. The first one is the node field which contains the best node (or null if no node could be found). The second one is the position field which contains the closest point on that node to the query point. On grid graphs, the nodes are thought of as squares so the position field will then contain the closest point inside that square to the query point. On navmesh based graphs (RecastGraph and NavMeshGraph) the position field will contain the closest point on the closest triangle. Point nodes do not have a surface so the position will just be set to the node's position.

Accessing graphs

All graphs are stored in the Pathfinding.AstarData class. It contains an array with all the graphs and there are a bunch of convenience methods for finding graphs in it. The quickest way however is to use the shortcuts that are provided. For each type of built in graph there is a field which points to the first graph of that type.

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");

Getting nodes in a graph.

The different graphs types store their nodes in different ways. The grid graph for example stores all nodes in a huge array which can be indexed to easily get a node at a specific cell index. The recast graph stores all nodes in arrays in separate tiles.

The generic very high-level way to get all nodes in a graph is by using the GetNodes method which exists on all types of graphs. It takes a callback which will be invoked for each node. The reason it uses a callback instead of an iterator is because callbacks are significantly faster than iterators and for large graphs that does make a difference.

var gg = AstarPath.active.data.gridGraph;
gg.GetNodes(node => {
// Here is a node
Debug.Log("I found a node at position " + (Vector3)node.position);
});
Warning
Do not update the data in the nodes. This can interfere with pathfinding that might be running at the same time (especially if using multithreading). To safely update node data you need to do that inside a safe callback. You can request a safe callback using AstarPath.AddWorkItem.
See Also
Graph Updates during Runtime

GridGraph

Grid graph nodes are stored in a large array. It is indexed by the coordinates of the node so they can be accessed easily.

var gg = AstarPath.active.data.gridGraph;
int x = 5;
int z = 8;
GridNode node = gg.nodes[z*gg.width + x];

There are some cases where you want to change the size of a grid graph during runtime. Then you can modify either the unclampedSize field. Which is the size of the grid in world units. Or you can use the SetDimensions method. After you have changed the width or depth of the graph you need to recalculate it using 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

It is also possible to move the grid graph without recalculating it using the RelocateNodes method. The same method is also available for other graphs, but then you have to calculate the necessarily matrix yourself.

Layered Grid Graph

The layered grid graph works almost like the grid graph. However the nodes are not ordered in exactly the same way. Since layered grid graphs can contain several layers. An additional layer coordinate is needed.

var gg = AstarPath.active.data.layerGridGraph;
int x = 5;
int z = 8;
int y = 2; // Layer
LevelGridNode node = gg.nodes[y*gg.width*gg.depth + z*gg.width + x];

NavmeshGraph/RecastGraph

Recast graphs divide the nodes into a number of tiles. The individual tiles are stored in an array in the same way as the grid graph stores its nodes. Inside each tile, the nodes are stored in an array without any inherent order. However all nodes are also added to a axis aligned bounding box tree AABB Tree in order to be able to query for the closest node to a point in an efficient manner. Navmesh graphs work exactly the same as recast graphs however they always use a single 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

Point graphs simply store the nodes in an array without any inherent order.

Point graph nodes also contain a field for the GameObject they were created from (if any) which can be useful for all kinds of purposes.

var node = AstarPath.active.GetNearest(transform.position).node;
var pointNode = node as PointNode;
if (pointNode != null) {
Debug.Log("That node was created from the GameObject named " + pointNode.gameObject.name);
} else {
Debug.Log("That node is not a PointNode");
}

You can also add nodes to a point graph during runtime:

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);
// Required because we have changed connectivity of the graph
ctx.QueueFloodFill();
}));
See Also
Graph Updates during Runtime which among other things explains more about the QueueFloodFill call.