Set target navigation layer/region in addition to target position


I have a multi-layered grid that I set up navigation for, which works great in most cases. Sometime I use bridges, however, which means having two overlapping nav regions with different layers (one for the bridge on, say, layer 2, and one for the surface below it on layer 1). This still works great until I set my navigation target to a point on the bridge (a point contained by both regions). It seems to perform a coin flip when choosing which region to navigate to (either the bridge itself or the surface below it), so it’s clearly capable of navigating to the point in either region. I want to be able to specify which nav region or layer to navigate to in addition to the vector2 itself. Is there a way to do this?

I can’t just set the change the enabled navigation layer of the agent because to get to the target it may need to traverse other layers (e.g. going up and down ramps). I’m currently working on what I consider a hack where I will use get_current_navigation_result() to analyze the current path after calculating it and if the owner of the final point is not the region I desire then I will “flip the coin” again until I get the desired result. If this works it will be ugly and expensive, however.

I can’t upload an attachment because I just made this account.

Stacked navmesh surfaces are not allowed at all in navigation mesh context as it breaks the logic.

With 2D navigation as long as you are using the same navigation map everything ends up on this flat plane and gets merged together no matter the “layer”. E.g. your “bridge” is merged with the “ground” below as such pseudo 2D verticality is not supported.

The navigation layers bitmasks are for disabling polygons in the actual path search.

If it’s not officially supported then so be it, but “pseudo 2D verticality” is working perfectly for me, if I could upload a video I could demonstrate it. I have a nav region for the upper layer (nav layer 2), one for the lower layer (nav layer 1), and one for ramps between them (nav layer 1 and 2). My character seamlessly passes under the bridge (I change its z-index when it exits the ramp) to reach points on nav layer 1 and walks on top of the bridge to reach points on nav layer 2, in both cases moving to the ramp to change level. I’m sure the regions are all flattened under the hood (like everything in 2D) but by properly setting up the layers as I’ve described they accomplish “pseudo 2D verticality”.

Either way, the hack I described in my original post worked. Hopefully the feature I requested becomes officially supported in the future so I can dispose of it.

It may work in your specific project atm but overlapping navigation mesh polygons easily creates navigation map merge errors. Merge errors break the pathfinding so is not a real solution that can be applied or recommended for other projects.

Instead of switching the layer bits you would need to switch the navigation maps to avoid all those conflicts as each navigation maps merges its own navigation mesh surface.

Really wish I could post an attachment but please see the ascii doodle below.

________ ………………………___________
—|……|—-|……^2 (bridge) |__________|
….|……|<-1&2 (ramp)…………………………

The bridge nav region, of nav layer 2, overlaps the ground nav region “below” it, of nav layer 1. This works as desired (as I described previously). Are you saying it shouldn’t? I’m not getting any errors.

The navigation map rasterizes the navigation mesh polygons per edgekey, the two unique vertices for an edge. If more than 2 edges start to overlap it creates merge errors as that would be a logical error when surfaces overlap or intersect.

So in that situation as long as there are no polygon edges “below” or “above” it avoids merge errors but as soon as something would be moved there (or ends up randomly due to a navmesh rebake) the pathfinding would break.

I think I understand, so I’m in the clear if I make sure the edges from different regions don’t perfectly overlap, shouldn’t be an issue. Regarding my original issue, that when these regions do overlap and a navigation path starts or ends a path in this overlap, there is no way to specify which region it should start and end in, is there a way to work around this besides the hack I described? If not, could it be added? Or is this an unintended use case?

Edit: Bear in mind, my hack only works because the map has the data already, so it’s clearly possible to support. The data I’m referring to is the NavigationAgent2D.get_current_navigation_result().path_rids.

You can exclude certain regions with the navigation_layers bitmask in a path query. You can not “layer” how a navigation map merges the navigation mesh polygons or what regions gets picked when things already overlap and all regions have the same bitmask. Whatever gets picked first in the search gets used.

The only way to stack navigation mesh surfaces reliably is by using different navigation maps and placing the overlapping regions on different maps, then querying whatever map is needed for a path and stitching the two maps together with a higher layer, e.g. a waypoint system.

Frankly there is a reason why all those old-schoold 2D games were done with waypoint or grid navigation as they do not care about surface logic like a navmesh system does. The options for that in Godot are AStar2D and AStarGrid2D. Many 2D-looking games these days are also done with 3D engines. It makes verticality problems and layering become a non-issue when using a 3D engine with 2D assets that are just “layered” on the y-axis.

I understand now, thank you for explaining. Would there be a way for me to leverage the 3D nav system without converting my entire project to 3D?

You can control everything with the NavigationServer. Technically there is only a 3D server anyway as 2D converts to 3D and back but all the 2D nodes have no interface to handle anything 3D related. So you would need to do everything with scripts if you do not want to rebuild your scene in 3D.