Create a graph dynamically

I have a Terrain object that gets generated runtime. How do I create a graph based on that terrain dynamically? If there is a section in tutorials describing this I would appreciate a link to it; all the tutorials I could find describe generating graphs in the inspector, not procedurally.

Just by playing around with the API I understand I have to populate the AstarPath.active.graphs property with an instance of a graph. In my case, I’m assuming, that would be a Recast graph (RecastGraph). How do I instantiate it?

I have a pro version, if that’s relevant.

Thanks

This is where I got so far. The code below generates a GridGraph based on my terrain.

var graph = (GridGraph) AstarPath.active.astarData.AddGraph(typeof(GridGraph)); graph.width = width; graph.depth = depth; graph.center = GetTerrainCenter(); graph.nodeSize = 1f; graph.UpdateSizeFromWidthDepth(); graph.collision.heightMask = LayerMask.GetMask("Terrain"); AstarPath.active.Scan();

The question I have now is as follows. I want to use the Tags feature of this package by marking water-covered parts of my terrain unwalkable for my units. I understand there is an UpdateGraphScene script but since I’m doing this procedurally I can’t use it.

AstarPath marks everything as walkable, including water (or rather “underwater”, because essentially raycasts hit the bottom of the water bodies), because the collision mask is set to the terrain layer; thus, my water plane, which is on the Water layer, is ignored. If I set the layer mask to include water and terrain, the only thing that changes is that raycasts start hitting the surface of water, but it’s walkable all the same.

http://arongranberg.com/astar/docs/graph-updates.php says for graph updates (and setting walkability is an update of a graph, essentially) done procedurally I’m supposed to use GraphUpdateObject and override the Apply(GraphNode node) function. This is of little use, however, because GraphNode contains no information about the layer that the original height testing raycast landed on. I do have access to node.position, of course, so I could do another raycast and see what it hits (hit.transform.gameObject.layer), but I wonder if there is a more efficient way of doing this.

Thanks

Hi

I think what you should do is to change the collision mask (as well as the height mask that you have already changed) to include water. When doing that the rays will hit the water and then become unwalkable since the collision testing detected an obstacle.

graph.collision.heightMask = LayerMask.GetMask("Terrain") | LayerMask.GetMask("Water"); graph.collision.mask = LayerMask.GetMask("Water");

I think this is the easiest approach.

Thank you for the reply.

It never occurred to me that I could use water as an obstacle. This will work, at least as long as I only have land units.

However, if at any point I decide to introduce naval units I will have to build a new graph covering essentially the same territory except all ground nodes will be unwalkable and water will be walkable. Having two graphs for the same terrain seems a waste, especially considering that the tags feature exists specifically for this.

I’m assuming there is no built-in way to handle this kind of situation for dynamically generated terrains? If that’s the case, it’s fine, I can implement the required raycasts myself or maybe I could preserve the layer/tag (Unity tag, not A*) information about the hit.transform.gameObject when AstarPath fires raycasts during the height testing. I just wanted to make sure I won’t be reinventing the wheel here.

Hi

Is the water at the same Y coordinate everywhere?
If that is the case you could cheat a bit and override the Apply method in your own GraphUpdateObject and do something like:
public void Apply ( GraphNode node ) { if ( ((Vector3)node.position).y < 100 ) { node.tag = 1; } }

If that doesn’t work… yeah, you probably have to do those raycasts. There are ways to get to the information, but it requires more code than it is worth.

Perfect, this will work.

Thanks again for the quick support!