Creating NavigationRegion2D from TileMap Data

Godot Version

4.2

Question

I’m currently working on something similar to Navigation on a procedurally generated TileMap with obstacles, and stumbled across that thread while trying to figure out how to add static colliders into my scene using a TileMap navigation and have them respected. Based on other sources in which @smix8 has written on the topic (mostly GitHub issues) and this thread, my path forward seems to be to:

  1. Disable navigation on my TileMap
  2. Create a NavigationRegion2D
  3. Create a NavigationPolygon
  4. Somehow get the NavigationPolygon to recognize my TileMap mesh
  5. Somehow get the NavigationPolygon to recognize my StaticBody2D elements

That all makes conceptual sense to me, but what’s not clear is whether I need to script up a solution like is done in the linked thread, or if it’s something I can setup entirely from the UI. I’ve messed with the NavigationPolygon and its Source Geometry Mode, both attempting to use the root and group modes with no success yet.

What I’m currently experiencing is the following:

  • If I use the TileMap navigation and add a StaticBody2D to my scene between an agent’s source and destination, the agent gets stuck on the collider. This makes sense, because it continues to try and navigate through the collider because it’s not aware of it.
  • If I uncheck the TileMap navigation (leaving out the StaticBody2D for now) and create a NavigationRegion2D and a NavigationPolygon under it, I can’t find a configuration in which my agent moves at all. I’m not sure if I’m missing a step here, but I expected it to detect my TileMap navigation data and use that.

So my actual question is, can I achieve what I’m trying to in the UI?

I am still very new to the engine, but maybe this helps. This is my understanding:

You can to it completely from the UI. When you add a NavigationRegion2D and a NavigationPolygon, make sure the Polygon covers the entire map. Then click Bake Navigation Region after you select the NavigationRegion2D in the scene tree.

How I made it work:

  1. I added the StaticBody2D elements as children of the TileMap in the scene tree.
  2. I set the NavigationPolygon’s Source Geometry Mode to Group With Children and the Source Geometry Group Name to navigation; I then added the TileMap to the navigation group.
  3. On the TileSet, I added collision polygons to the Physics property of the tiles.

Hope this helps. I am a total beginner, so I cannot help further. Step 2 can likely be solved in a better way that I am not aware of. Other settings I tried didn’t work.

Good luck!

2 Likes

First off, thanks so much for your reply!

I’ve done some manual creation of NavigationPolygon before, by setting out the points and then baking, but was hoping that since I’d already done the work of adding the navigation layer to my TileMap tiles, that it would somehow pick that up for my navigation region as a basis, rather than having to create a polygon manually.

I’m assuming you added StaticBody2D elements as children of the TileMap in order to use Group With Children with them?

When you say you added collision polygons to the Physics property of the tiles, do you mean the tiles used for rendering the StaticBody2D elements, or something else?

Yes.

I meant the tiles of the TileSet of the TileMap. Maybe you have solid tiles like walls that shouldn’t be navigated.

1 Like

For baking a TileMap you do not need to draw / add a bounding outline, you can bake the TileMap directly with the NavigationRegion2D. The TileMap adds all its cells with a navigation polygon on the first TileMapLayer as traversable, while all the TileMap cells with a physics collision polygon are added as obstructions that “cut” into the navmesh later. It is important to note that only the first TileMapLayer gets parsed and you can not stack / overlap navigation polygons.

If the TileMap is not a direct child of the region node do as schemar suggested and switch the NavigationPolygon to parse by groupname. Parsing by groupname makes the placement of the parsed nodes in the SceneTree irrelevant, the only downside is that you need to add this groupname to all the main nodes that you want to have parsed.

1 Like

Okay, the step I was missing was actually performing the bake. It was a little weird to create an empty polygon and bake it, because it showed nothing.

There’s a few interesting nuances here that I’m going to note that might help someone in the future:

  • The Root Node Children mode of the NavigationPolygon Source Geometry Mode property seems to refer to the NavigationRegion2D as the “root node”. So I was assuming it meant the root node of the scene, and that it would pick up anything. Thanks for helping sort that out.
  • The z ordering of my nodes impacts what debugging elements I can see. I have Visible Navigation checked, and seeing that remain blank sometimes was confusing. What seems to be happening is that elements later/lower in the scene tree will show up on top of those higher. So when using the root mode, I saw my debugging area. When using the group mode, I wasn’t seeing it because my NavigationRegion2D was higher in my scene tree. Moving it lower let me see those elements, as well as changing the Z Index of my TileMap lower (e.g. to -1).

With all that, I now have this, which is roughly what I was after!

So I think I’ve finally cracked it, thank you both. I had to actually bake the polygon after setting it up correctly. I’d argue the “Root Node Children” mode for the source geometry is a little oddly named, but it seems like a lot of these improvements are works in progress, so I imagine the documentation will catch up eventually!

The 2D navmesh debug is currently rendered directly by the nodes themself as part of their canvas rendering. So the debug is affected by some of the render and transform properties that users set on the node level as those get inherited from the parent canvas.

The reason why the NavigationRegion2D does (no longer, it did before) not auto-create the polygons is because as soon as polygons get a little more complex it would lag the editor all the time when users tried to drag the polygon handles around. Baking a navmesh is not exactly a quick process and the editor can not handle it reliably on a background thread, so it runs on the main-thread freezing the editor until it is done. It also mirrors the 3D navmesh workflow.

The SceneTree Viewport is named “root” and often referred to as “root node” but there are many other “root nodes” across the engine like used in graphs and functions. Everytime you tell something where to start some recursive function process you pick a “root node”. Admittedly you are not the first to make this quick connection and think it is the SceneTree root, it happens occasionally. I think the documentation clears this up and mentions it in the bake functions and other places. The name has been already used and is a stable for years with the 3D navmesh baking so it is not a new invention.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.