Creating NodeLink in Runtime


I have the Situation where the player can dynamically create ladders for the NPCs, so they need to be able to find their way up to the second floor.
After looking for a while i found this quote from aron on this thread (Ladders on navmesh / links are too far away from nodes):

it seems as the other user had success with creating that connections but unfortunatly isnt elaborating any further on it.

What i’m doing right now during runtime is this (Keep in Mind - graph[0] is my recastgraph and graph[1] is my pointgraph):

var bottomFloor =[0].GetNearest(ladderNodePositions[0].position).node;
var bottomLadder =[1].GetNearest(ladderNodePositions[0].position).node;
var topFloor =[0].GetNearest(ladderNodePositions[1].position).node;
var topLadder =[1].GetNearest(ladderNodePositions[1].position).node;

Debug.Log(“Creating NodeLinks…”);
bottomFloor.AddConnection(bottomLadder, (uint)(bottomFloor.position - bottomLadder.position).costMagnitude);
bottomLadder.AddConnection(bottomFloor, (uint)(bottomLadder.position - bottomFloor.position).costMagnitude);
topFloor.AddConnection(topLadder, (uint)(topFloor.position - topLadder.position).costMagnitude);
topLadder.AddConnection(topFloor, (uint)(topLadder.position - topFloor.position).costMagnitude);

It seems as if the nodes will be created correctly, but somehow the seeker refuses to traverse over the pointgraph.
Any suggestions? I’d be happy for any suggestions to solve this problem!!

I attached a screenshot to show that the nodes are actually being connected, but the pathing isnt working as expected.

Cheers and thanks upfront!


If you are doing this during runtime then you will need to recalculate some metadata that the pathfinding system uses.
In particular you will have to do something like this:

// Make sure the code is executed when all pathfinding threads have been paused AstarWorkItem(ctx => {
    // Modify connections here...
    // Recalculates some meta info regarding which nodes are reachable from which other nodes (these are the colors you see in the scene view)

See for more information.

Thanks a lot! That did the trick! :slight_smile:

One more question: is it possible to add/remove nodes on a recast-graph in runtime without having to recalculate the entire graph and by just updating a tile?

i figured that its possible to update specific nodes in runtime using bounding boxes, but can you add them as well?

for some reason the funnel modifier doesnt work when combining a point and a recast-graph, and being able to just add 2 nodes (the ladder-positions) to the recast graphs and connect them should do the trick. (also it would seem a bit “cleaner” that way)

thanks for the quick reply!


That sounds odd. Do you have a specific example where this doesn’t work? It should work out of the box.
Also. You might want to have a look at the NodeLink2 component which does all this for you. It creates 2 new nodes on a separate point graph and connects them to the appropriate nodes on other graphs. Unfortunately that component is not that well documented at the moment. I’m sorry about that.

You should be able to replicate the problem creating a similar setup as in my images:
-) Create 2 overlapping Cubes with some distance to each other
-) Create empty-GameObjects for path-Start-Position and path-End-Position (one on each cube)
-) Create an empty GameObject where you want the ladder to be (Start and End).
-) Attach LinkGraphs.cs (LinkGraphs.cs.txt (2.2 KB)) and the Funnel modifier to an empty GameObject
-) Fill in required variables into LinkGraphs.cs
-) In the Pathfinder, create a Recast and a Point-Graph (make sure the recast creates a navmesh on the surface of both cubes). Create the Recast first, to make sure he is data.graphs[0].

Now when you run the scene, the pathing (+Funnel) works - ignoring the ladder (test by pressing “P”).
When you press “Space”, the ladder stitches the two nav-meshes together.
If you try to find a path now, the funnel will throw an error. If you remove the funnel modifier, then the pathing works again (using the ladder!).

The Error thrown by the Funnel Modifier:

Exception: Unsupported node type or null node
Pathfinding.Funnel.SplitIntoParts (Pathfinding.Path path) (at Assets/AstarPathfindingProject/Utilities/Funnel.cs:99)

Also, is it possible to add/remove a node to a recast-graph in runtime (not only edit it)? This would avoid the need for any additional graphs, wouldnt it? Thanks upfront!

I figured its even easier to replicate… just trying to use the funnel modifier on a pointgraph already throws the error.

Apparently line 42 in the Funnel.cs says:

if (nodes[i] is TriangleMeshNode || nodes[i] is GridNodeBase)

by adding “|| nodes[i] is PointNode” the funnel seems to work again, yet yielding weird results (skipping the entire path and creating direct connections from start to end).

Also, is it possible to add/remove nodes on a recast-graph in runtime without having to recalculate the entire graph and by just updating a tile? :slight_smile:

Thanks upfront!

Ah. Right. That’s how it behaves.
It has explicit support for it when using the NodeLink2 component, but not otherwise.

In what way? Recast graph nodes are always triangles, you cannot add any point nodes of any kind to them.

well, then my question would be if its possible to add/remove triangles in runtime (i’m aware of navmeshcut - the bigger challange is the “adding” actually - for ladders, multi story buildings, etc…). i’m thinking of including small navmeshes in the construction-parts of the buildings (like a square on a ground floor for example), and adding them to the recast-graph in runtime. if that would be possible, i hope that i woudnt need to scan the entire graph/tile and that way, speed up the graph-recalcuation?

There is the NavmeshAdd component which does that. However note that it will not connect those triangles to anything else in the graph. Though you can add e.g NodeLink2 components to do that.

It is possible to connect the triangles directly to the rest of the graph, I did that for another game I was working on. However I strongly discourage you from trying to do that as it caused so many problems down the line with floating point errors.