How to properly subclass GridGraph

I’m trying to subclass the GridGraph to add some extra functionality like connections to other graphs but it seems that when i do that the nodes disappear. Everything works if I leave the graph type as GridGraph though.

I do have the Editor class created and the graph shows up correctly in the inspector.

In my GridGraph subclass I’m overriding just the one method UpdateNodePositionCollision
Is this not enough or is something missing here?

public override void UpdateNodePositionCollision(GridNode node, int x, int z, bool resetPenalty = true) {
    node.Penalty = 0;
    node.Walkable = true;
    node.WalkableErosion = node.Walkable;
}

Turns out this was correct but when I created the graph it would only work if i waited a frame before scanning or scanned it twice (that’s why when I scanned by clicking Scan in the inspector it also worked right)

yield return 0;
gg.ScanGraph();

Can you please explain why that is?

Hi

In the editor when not playing the graph will be automatically recalculated when the width/depth has changed and the last scan was not too slow. It can only do this if it knows it is exactly a grid graph though (since subclasses might change some behavior), so it would not be done for your graph type. Scanning the graph using the ‘Scan’ button should work however. When playing the behavior should be identical. Maybe this is what caused what you are seeing?

Thanks for the quick response, I’m only referring to runtime, are you saying the scan happens automatically in that case also?

What is happening is that this works but only if I use the yield return 0 to wait for a frame.
I tried replacing gg.ScanGraph() with AstarPath.active.Scan() with same results. It happens both when using GridGraph and when using my subclass.

GridGraph gg = AstarPath.active.astarData.AddGraph(typeof(GridGraph)) as GridGraph;
gg.center = center;
gg.nodeSize = 0.2f;
gg.width = 4;
gg.depth = 4;  
gg.collision.collisionCheck = false;
gg.collision.heightCheck = true;
gg.maxSlope = 60f;
gg.UpdateSizeFromWidthDepth();

yield return 0; // <-- Without this the scan doesn't work
gg.ScanGraph();

Doing the scan twice also works presumably because the first scan is the delay:

gg.ScanGraph();
gg.ScanGraph();

Hi

Ok, no that should matter for runtime (though make sure the A* component is not visible in the inspector just to make sure that does not interfere, it should not, but it will do some serialization).

It might be because you are trying to scan during Awake and the AstarPath class has not had its Awake method run yet (though I guess it should have since AstarPath.active is set)?

You should avoid using the ScanGraph method (in fact in later versions it has been renamed to ScanInternal), it will not update all metadata.

Oh, and if you are scanning the graphs manually, you can set A* Inspector -> Settings -> ‘Scan On Awake’ to false.

“Scan on Awake” is disabled, just double-checked to keep my sanity :slight_smile: . I’m actually adding the graph when the user clicks their mouse so it’s definitely after Awake phase. I’m having the same issue with both methods: AstarPath.active.Scan() and gg.ScanGraph().

What is the reason for you wanting to remove ScanGraph? I much prefer calling it since this new graph is tiny and my main graph is huge. What would you recommend for performance in this case?

I will be adding a bunch of little graphs based on user actions so I was hoping to just have to scan those and then maybe Flood Fill for any connections between the little graphs and the main graph.

Hi

Scanning just a single graph is not really supported. You can technically do it, but you will have to look out for edge cases esp. when adding custom connections.

When you say the scan does not work, what exactly does not work? Does it fail with an error?

I should clarify, it doesn’t fail but just scans incorrectly, everything is “unwalkable”. When I use the delay or scan twice it works fine.

Are they specifically unwalkable or do the nodes simply not exist? (you can click the info button in the inspector).

Ok I stand corrected, they are walkable just display as unwalkable in the scen view. So this was working just not being reflected in the scene view correctly. The issue is just with the scene preview. The preview comes in very handy for verifying grid-to-grid connections. Do you think this is a bug with the preview?

Is there a way to force a preview refresh?

How do you see that they are unwalkable?
Could you post a screenshot?

Ok figured out what was happening. I was executing a graph update on the main graph using AstarPath.active.UpdateGraphs(guo); right before adding the new graph and i think that update was in the queue interfering with the scan of the new graph.

How can I queue up the call to AstarPath.active.Scan() so everything happens in order? I mean the one frame delay works right now but seems a little hacky.

Hi

Hm… Yes, looking at the code it doesn’t actually ensure that no graph updates are being performed at the same time, it only ensures that pathfinding has been stopped (I will have to investigate that further), but if a graph update would take more than 1 frame to calculate it might still be running. Grid graph updates all complete in a single frame though, so I don’t think that would be the problem… Except possibly the flood fill which can be done in a separate thread.

You can call AstarPath.FlushWorkItems to ensure all grid graph updates (and all other kinds of updates) have been completed. If you are using an earlier version than 3.8.5 then the default parameters are pretty bad and will not do what you want. You will want to call AstarPath.instance.FlushWorkItems(true, true) in that case.

I am on 3.8.2 and that worked. Interestingly, now that I’m calling FlushWorkItems only AstarPath.active.Scan() works, calling gg.ScanGraph() throws an error (I know you said to use AstarPath.active.Scan() just thought it was worth noting)

This is the exception

	Exception: Trying to initialize a node when it is not safe to initialize any nodes. Must be done during a graph update. See http://arongranberg.com/astar/docs/graph-updates.php#direct
	Pathfinding.PathProcessor.InitializeNode (Pathfinding.GraphNode node) (at Assets/AstarPathfindingProject/Core/Misc/PathProcessor.cs:196)
	AstarPath.InitializeNode (Pathfinding.GraphNode node) (at Assets/AstarPathfindingProject/Core/AstarPath.cs:1404)

Nice!

Yeah, that’s one of the things ScanGraph will not configure (it was not intended to be used from external scripts, which is why it has been renamed to ScanInternal). When you call that, the pathfinding threads might still be running and it is not safe to modify the graphs when they are (as that exception indicates).

It worked previously because a graph update was running at the same time.

Makes sense, thanks for helping me figure this out. The plugin works awesome, saved me a ton of work. :slight_smile: