A* Pathfinding Project  3.6.6
The A* Pathfinding Project for Unity 3D
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Events Macros Groups Pages
Graph Updates during Runtime

Overview

Many graphs supports updating during runtime without a complete rescan. Best implemented is the GridGraph and PointGraph, but navmesh based ones also has support for it.
Graph Updates can either be done using the GraphUpdateScene component which does all the heavy work for you or using scripting which is done by calling a central function in the AstarPath class with either a Bounds object or a Pathfinding::GraphUpdateObject (which is what the GraphUpdateScene component actually does in the background).

AstarPath.active.UpdateGraphs (myGraphUpdateObject);

The function will then put the task in a queue to be carried out before the next path calculation. It has to be put in a queue because if it carried out directly, it might interfere with pathfinding, especially if multithreading is on, and cause all kinds of errors. This means that you might not see an update of the graph directly, but it will always be updated before the next pathfinding calculation starts (almost always, see AstarPath.limitGraphUpdates ).

Recast graphs can be pseudo-updated using navmesh cutting. Navmesh cutting can cut out holes for obstacles in the navmesh, but cannot add more navmesh surface. See NavmeshCut.

Using the GraphUpdateScene component

The GraphUpdateScene component is really easy to use. Create a new empty GameObject and add the component to it, it can be found in Components–>Pathfinding–>GraphUpdateScene.
When you have added the component, you should see something like the image below.

The area which the component will affect is defined by creating a polygon in the scene. If you make sure you have the Position tool enabled (top-left corner of the Unity window) you can shift-click in the scene view to add more points to the polygon. You can remove points using shift-alt-click. By clicking on the points you can bring up a positioning tool. You can also open the "points" array in the inspector to set each point's coordinates.
In the inspector there are a number of variables. The first one is named "Convex", it sets if the convex hull of the points should be calculated or if the polygon should be used as-is. Using the convex hull is faster when applying the changes to the graph, but with a non-convex polygon you can specify more complicated areas.
The next two variables, called "Apply On Start" and "Apply On Scan" determine when to apply the changes. If the object is in the scene from the beginning, both can be left on, it doesn't matter since the graph is also scanned at start. However if you instantiate it later in the game, you can make it apply it's setting directly, or wait until the next scan (if any). If the graph is rescanned, all GraphUpdateScene components which have the Apply On Scan variable toggled will apply their settings again to the graph since rescanning clears all previous changes.
You can also make it apply it's changes using scripting.

GetComponent<GraphUpdateScene>().Apply ();

The above code will make it apply it's changes to the graph (assuming a GraphUpdateScene component is attached to the same GameObject).

Next there is "Modify Walkability" and "Set Walkability" (which appears when "Modify Walkability" is toggled). If Modify Walkability is set, then all nodes inside the area will either be set to walkable or unwalkable depending on the value of the "Set Walkability" variable.

Penalty can also be applied to the nodes. A higher penalty (aka weight) makes the nodes harder to traverse so it will try to avoid those areas.

The tagging variables can be read more about on this page: Working with tags.

Using Scripting

When updating is carried out, all graphs will be looped over and those which can be updated (all built in ones) will have their UpdateArea function called (i.e be updated).
Each node is updated by the graphs calling Pathfinding::GraphUpdateObject::Apply sending each affected node to it, the Apply function will then change penalty, walkability or other parameters specified. Graphs can also use custom updating logic, such as the GridGraph (see Updating GridGraphs). You do not have to understand all different function calls to be able to use it, those are mostly for people who want to mess around with the source code.

Changing penalty

A common task is to add a penalty (weight) to some nodes to make it be avoided by the algorithm, in other words make the area slower/harder to traverse. This can be done relatively easy using GraphUpdateObjects.

//using Pathfinding; //At top of script
GraphUpdateObject guo = new GraphUpdateObject(myBounds);
guo.addPenalty = 10000; //Here goes the penalty to apply, you need quite large values usually

The myBounds variable referred to is a UnityEngine.Bounds object. It defines an axis aligned box in which to update the graphs in.

If you don't need to update walkability when using a grid graph or connections when using a point graph, you can set updatePhysics (see Updating GridGraphs) to false to avoid unnecessary calculations

guo.updatePhysics = false;

Updating GridGraphs

The GraphUpdateObject::updatePhysics variable matters a lot when updating grid graphs. If it is set to true, all nodes affected will have their height recalculated and then checked if they are still walkable. You usually want to leave this to true when updating a grid graph.

A common misstake is to create a new obstacle in the scene, and do something like this:

GameObject obstacle = GameObject.Instantiate (obstaclePrefab,somePosition,Quaternion.identity) as GameObject;
AstarPath.active.UpdateGraphs (obstacle.collider.bounds);

And expect the area under the obstacle to become unwalkable. The misstake is often that one does not check that the obstacle is in a layer which would make the nodes unwalkable in the first place. The GridGraph's settings for collision checking has a mask field, one must make sure the obstacle is in a layer contained in that mask.

Internal Workings

When updating a GridGraph, the GraphUpdateObject's Apply function will be called for each node inside the bounds, it will check the GraphUpdateObject::updatePhysics variable, if it is true (which is the default value), the area will be expanded by the diameter of the Collision Testing and every node inside the area will be checked for collisions. If it is false, however, only the Apply function will be called for the nodes inside the area (not expanded) and nothing else will be done.

Updating Navmesh based Graphs

Navmesh based graphs (NavMeshGraph and RecastGraph) only have support for updating penalty, walkability and similar on already existing nodes. New nodes cannot be created using GraphUpdateObjects. The GraphUpdateObject will affect all nodes/triangles which intersect or are contained by the GUO's bounds.

Updating Point Graphs

Point graphs will call Apply on every node inside the bounds and also, if GraphUpdateObject::updatePhysics is set to true (default true), it will recalculate any connections which passes through the bounds object.

Note
Updating Point graphs is only available in the pro version of the A* Pathfinding Project.
A* Pro Feature:
This is an A* Pathfinding Project Pro feature only. This function/class/variable might not exist in the Free version of the A* Pathfinding Project or the functionality might be limited
The Pro version can be bought here

The Graph Update Object

The GraphUpdateObject contains some basic variables on how to update each node. See documentation for the Pathfinding::GraphUpdateObject for more info.

Inheriting from the GraphUpdateObject

Classes can inherit from the GraphUpdateObject to override some functionality.
Here's an example of a GraphUpdateObject which moves nodes by some offset while still keeping the base functionality.

using Pathfinding;
public class MyGUO : GraphUpdateObject {
Vector3 offset = Vector3.up;
public override Apply (Node node) {
//Keep the base functionality
base.Apply (node);
//The position of a node is an Int3, so we need to cast the offset
node.position += (Int3)offset;
}
}

You could then use that GUO like this:

public void Start () {
MyGUO guo = new MyGUO ();
guo.offset = Vector3.up*2;
guo.bounds = new Bounds (Vector3.zero,Vector3.one*10);
}