1

I have a tilemap in godot, but all tiles are obstacles and provide collision. Only cells without any tile are walkable. I'm now trying to add navigation via Navigation2D node. As far as I see there is no way to tell it "everything is walkable, but not where these tiles are" (all one can say is "this part of the tile is walkable", but in my current setup there is no tile at the walkable space).

As a workaround I tried to set every cell with no tile to a "dummy tile" which is fully walkable with the following code:

func _ready():
    for x in size.x:
        for y in size.y:
            var cell = get_cell(x, y)
            if cell == -1:
                set_cell(x, y, WALKABLE)

But the Navigation2D node does not recognize these tiles. If I place the WALKABLE tile manually, everything works as expected.

I think I might be hitting this issue, and need to call update_dirty_quadrants() but this does not fix the problem.

I tried this with the versions 3.0.6stable, 3.1Alpha2 and a recent commit 9a8569d (provided by godotwild), and the result was always the same.

Is there anyway to get navigation with tilemaps working, without placing every tile beforehand manually?

syntonym
  • 7,134
  • 2
  • 32
  • 45
  • How did you get past this? Did you just use tiles everywhere? – MarkReedZ Dec 31 '18 at 20:37
  • I'm doing custom pathfinding with nodes for each "empty tile" generated in the way outlined in the post. So in a sense I did not get around the problem at all. – syntonym Jan 02 '19 at 12:58

2 Answers2

3

For anyone coming across this in the future, the 'dummy navigation tile' solution works now (using Godot 3.2.3). Put this script on the tilemap in question:

extends TileMap

# Empty/invisible tile marked as completely walkable. The ID of the tile should correspond
# to the order in which it was created in the tileset editor.
export(int) var _nav_tile_id := 0

func _ready() -> void:
    # Find the bounds of the tilemap (there is no 'size' property available)
    var bounds_min := Vector2.ZERO
    var bounds_max := Vector2.ZERO
    for pos in get_used_cells():
        if pos.x < bounds_min.x:
            bounds_min.x = int(pos.x)
        elif pos.x > bounds_max.x:
            bounds_max.x = int(pos.x)
        if pos.y < bounds_min.y:
            bounds_min.y = int(pos.y)
        elif pos.y > bounds_max.y:
            bounds_max.y = int(pos.y)
    
    # Replace all empty tiles with the provided navigation tile
    for x in range(bounds_min.x, bounds_max.x):
        for y in range(bounds_min.y, bounds_max.y):
            if get_cell(x, y) == -1:
                set_cell(x, y, _nav_tile_id)

    # Force the navigation mesh to update immediately
    update_dirty_quadrants()
LukeZaz
  • 300
  • 2
  • 5
  • 15
1

I couldn't find the ID from my tile in the autotiler (when checking in the editor, having the tilemap selected, these all show the same imagename.png 0). So instead of using the ID, I used the coordinates of the walkable blank tile in the Tileset. The code remains the same as LukeZaz', but with set_cell replaced by:

set_cell(x, y, 0, false, false, false, Vector2(7,4)); where Vector2(7,4) is the coordinate of the blank tile in my tileset that has the navigationpolygon on it. (Remember that coördinates start at 0)

(Godot 3.2.3.stable)