Path returned by Navigation2D.get_simple_path is displaced if parent Node is moved

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By alb.ots

Hi Folks,

I’m designing a simple map navigation system for a game which is based on clickable locations. Basically, you have a map, some locations within the map and a path between locations. Assuming the player cursor is on location A, you click on location B and it will move the cursor through the path until it arrives at location B. Furthermore, since the map is designed as a TileMap, I wanted to limit the movement to cells (so it is a grid movement).

I created a new map scene with the following organization:

Imgur

The reason I put Navigation2D under TileMap and define a Polygon for it (instead of using the polygons from the tileset within the tilemap) is that I sort of need to limit the size of the polygon within each cell of the TileMap to make grid movement easier.

An example instance of this scene is as below

Imgur

Each instance will have several locations defined (the YSorts are all specific location scenes that inherit from a base Location scene). The way this looks is as below

Imgur

I hid some objects from the scene to make it easier to see. I left two locations, City and Ruins, and as a test, I was charting the path between the City and the Ruins. If I have the Map transform at (0, 0), it works perfectly, see below:

Imgur

Each round sprite is a tile within the tilemap. I’m also displaying the navigation polygon, and red crosses are debug sprites I generate at each position of the path, in addition to the line of the path. My procedure to generate the grid movement path is to, given the path between the current position and the destination position, for each position in the path I calculate the tilemap position, then recalculate the world (local position), and then center the location position by adding half the tile size to each local position within the path. The code is as below:

A signal handler responds to a signal from each children location when it is clicked within a region around it, receiving the local position of the location; current_tilemap_position stores the cursor position in the tilemap. There is bunch of debug code which I’ll show the output for after the explanation. Here is the signal handler:

func _on_location_selected(location_position) -> void:

var current_position = map_to_world(current_tilemap_position)
current_position = compute_position_centered_on_tile(current_position)
var location_tilemap_position = world_to_map(location_position)

print("Navigation: ")
print("    -> From: {0}: {1} | global: {2}".format({"0":current_tilemap_position, "1":current_position, "2":to_global(current_position)}))
print("    -> To: {0}: {1} | global: {2}".format({"0":location_tilemap_position, "1":location_position, "2":to_global(location_position)}))

var raw_path = nav_2d.get_simple_path(current_position, location_position)
print("    -> raw_path: ", raw_path)

	
if raw_path:
	var path = compute_centered_path(raw_path)
	print("    -> centered_path: ", path)
	
	current_tilemap_position = location_tilemap_position
	myline2d.points = path
	myline2d.width = 3
	
	for pos in path:
		gen_debug_sprite(pos)

The other two functions are:

func compute_position_centered_on_tile(pos: Vector2) -> Vector2:

pos.x += cell_size.x/2
pos.y += cell_size.y/2

return pos

func compute_centered_path(path: PoolVector2Array) -> PoolVector2Array:

var centered_path: PoolVector2Array = []

for pos in path:
	
	var centered_pos = map_to_world(world_to_map(pos))
	centered_pos = compute_position_centered_on_tile(centered_pos)
	
	centered_path.append(centered_pos)	
	
return centered_path

This works fine when the position of Map is at (0, 0), with the output below:

Imgur

However, since I’m dealing with local position (on both map_to_world and get_simple_path) I wanted to test what happens when I move the Map to not be at (0, 0). It totally broke my paths! This is the result when Map is at (50, 50)

Imgur

and the output is:

Imgur

Now the weird thing is, even though get_simple_path is getting as input the positions (528, 240) and (1296, 176), its output starts at (570, 240) and goes to (1338, 218). I can’t figure it out what is happening here, since per the documentation, get_simple_path should operate over local paths, so the output should be fine. Furthermore, this dislocation seens to be proportional to how much I moved Map, since for moves less than (10, 10) the output is still correct. Can you folks help me here?

:bust_in_silhouette: Reply From: smix8

There is a warning on your Navigation2D node. With Godot 3.5+ the old Navigation2D is deprecated. It now no longer functions like the old documentation would state as it has not been updated since. The old pre 3.5 navigation did local pathfinding on the node while the new navigation uses the global Navigation2DServer which expects global positions on the functions. For some compatibility the old Navigation2D function get_simple_path() forwards to Navigation2DServer.map_get_path() but there is no local to global auto-conversion.