Hi everyone,

I am currently working on a tilemap, bigger than screen where I manage to move my player thanks to many existing tutorials.

What I am also trying to do, is to have NPCs moving using the same process from specific points (I do not want them to just wander everywhere, but let say, from cities to cities).

I believe I face two problems :
- I need to create path for every character even when the player is not on the tilemap
- I want them to move while my tilemap scene is off (Player is not on the world map)

For this matter, I created a dictionary on a one-shot effort (but it can be updated) that is supposed to provide for each cities, the distance with the other existing cities.

Nonetheless, it seems I am facing some troubles with the getsimplepath between two cities.
I tried to use it between tilemap cells coordinate. Between maptoworld coordinate and alway get an empty path...

I am certainly doing something wrong here... but I am wondering if the getsimplepath is actually able to calculate a path/distance or if I should determine the distance between to cities in a whole different fashion...

if it is of any use, I am doing the following :

This function search for a city on my map. When it finds one, it launches another function looking for relatives distances between this city an all other "visitable" ( = cities) tiles.

``````func city_distances():
var origin_cell = Vector2()
for x in range(map_size.x):
origin_cell.x=x
for y in range (map_size.y):
origin_cell.y=y
``````

The following function is called whenever a cities is found, it crawls the tilemap in search for any other cities, and is supposed to provide a path between the first city and any other cities. The path lenght (which my be a bad idea) is supposed to give me an idea regarding the distances between the two said cities:

``````func all_cities_distance(origin_cell): #from one cell, crawl the tile_dic to find distances for all cities
var temp_city_dist={}
var target_cell = Vector2()
for i in range(map_size.x):
target_cell.x=i
for j in range (map_size.y):
target_cell.y=j
var path = PoolVector2Array()
if \$Navigation2D/TileMap.tile_dic[target_cell].visitable == true && target_cell!=origin_cell:
#path = \$Navigation2D.get_simple_path(origin_cell,target_cell,false) #attempt with cell coordinate
return temp_city_dist
``````

Result is a nice dictionary with Distance:0 between all cities.... (path remains empty while debugging).

At this point, I am considering all options :D Including different ways to get the distance between two tiles from a tilemap....

Best regards,

Bk

Godot version 3.2.3
in Engine

(path remains empty while debugging).

That indicates to me that your Navigation2D node isn't set up properly. It seems to me that you are calling `get_simple_path()` with the correct arguments. Maybe try calling it with global positions and see if that gets you a path?

``````var tmap = \$Navigation2D/TileMap
var origin_local = tmap.map_to_world(origin_cell)
var target_local = tmap.map_to_world(target_cell)
``````

Here is a video demonstrating using a Navigation2D node on a tilemap: https://www.youtube.com/watch?v=0fPOt0Jw52s

Here is a video on general path finding that also shows the alternative AStar node path finding: https://www.youtube.com/watch?v=Ad6Us73smNs
The video is a bit older, since it was created Godot added a AStar2D node where you can work entirely with Vector2's instead of converting to Vector3's. It's very easy to download the code from that video and update it to use AStar2D.

by (3,906 points)
edited

Ok, so I tried while adding half cells but failed to get results. (path.size() always == 0)

What I am actually trying is to get a path for npc at the same moment I get one for the player. Trying to send it in a random location from there.
It requires a little bit of set up as I want to be able to switch back to a more desirable setting once I get what is wrong.
I might get a good run tomorrow...

A little bit more on this.

I hard coded "local coordinates" and tried to see if I could get a path.

here is the chunk of code (it is ugly but I want to solve this ^^') :

``````    var vector1 = Vector2()
vector1.x = 650
vector1.y = 400
var vector2 = Vector2()
vector2.x=800
vector2.y=600
print("temp path : ", temp_path)
``````

In the same script, are my player movement on click and my paths generator.
Went if copy this in my player movement event I get something :

temp path : [(650, 400), (736, 437.5), (806, 542.5), (800, 600)]

While my loop in the path_generator just...gives nothing :

temp path : [] path : [] temp path : [] path : [] temp path : [] path
: [] temp path : [] path : []

I am starting to feel there is something awkward and/or not ready when I call the path generator. So I will try to call it at the same moment I move my player to see if it changes anything...

ok so it worked when I called the `city_dstances()` at the end of the player movement func.

temp path : [(650, 400), (736, 437.5), (806, 542.5), (800, 600)] path
: [(351, 1732.5), (316, 1697.5), (246, 1592.5), (246, 1487.5), (316,
1382.5), (386, 1277.5), (456, 1172.5), (526, 1067.5), (596, 962.5), (596, 857.5), (596, 752.5), (666, 647.5), (666, 542.5), (666, 437.5),
(701, 367.5)] temp path : [(650, 400), (736, 437.5), (806, 542.5),
(800, 600)] path : [(351, 1732.5), (421, 1750), (526, 1697.5), (596,
1592.5), (666, 1487.5), (736, 1382.5), (806, 1277.5), (876, 1172.5), (946, 1067.5), (1051, 1015), (1156, 962.5), (1226, 857.5), (1331,
805), (1471, 805), (1611, 805), (1681, 787.5)] temp path : [(650,
400), (736, 437.5), (806, 542.5), (800, 600)]

I was initially calling `city_distances()` at the end of the `_ready()`:

``````func _ready():
\$Character.show()
\$floating_Label.hide()
map_size=Global.map_size
is_hovering = false
if Global.dic_cities_distances.size()==0: #if it has not previously been done, populates the city_distances dictionary. Has to be reperformed if a new city is added
city_distances()
``````

I do not get it as my code is not preparing anything fancy nor initiates things for the `\$Navigation2D` to work on click.

I would like to understand this..

From my understanding, the nodes at the bottom of the hierarchy have their `_ready()` functions called first then it goes up the tree from there. I would bet that `Navigation2D` nodes need to have their `_ready()` functions called before they will work properly. You can test which node is ready first pretty easily. Add this code to the node where you were calling `city_distances()` from `_ready()` (replacing the node path in get_node() to match yours, you can drag and drop the path from the scene tree on the left):

``````extends Node2D

var my_cool_var

my_cool_var = 'node'
print('nav is inside tree: ',  get_node("../Navigation2D").is_inside_tree())
``````

and add this code to your `Navigation2D` script (again replacing the node path in get_node() to match yours):

``````extends Navigation2D

var my_cool_var

my_cool_var = "nav"
print('node is inside tree: ',  get_node("../Node2D").is_inside_tree())
print('node is ready: ', get_node("../Node2D").my_cool_var != null)
``````

Hi, I am a little bit confused about what this is supposed to achieve.

I think I have enought material to get around my problem, but when I tried you thing is crashes stating I cannot call isinsidetree" on a null instance from my navigation2D.

There is nothing (no script) in my navigation2D so I added just this.

Is it a cross checking variable (navigation calls node's variable and tries to display it, while the node tries to call navigation's variable ?)

I will try to just go with distance calculus and check that on a given timer, my NPC movements func manages to get paths. Hope it works!

Sincerely thank you for you time and help !