Really really struggling to understand the tile map functions and getting them to return data

Godot Version

4.2

Question

Goal: I would like to get data from the tile the player clicks on, most importantly I would like to get which layer the tile is on. So if I have tiles (maybe in a pyramid shape) between layers 0, 1 and 2 then if the player clicks on the very “top” tile it will return: layer 2.

From the 6+ hours I have been struggling with this, it seems like godot 3.x had a get_cell function.
I haven’t been able to find anything like that with 4.x unless I am grossly misunderstanding it.
I’ve tried to use get_cell_atlas_coords() and get_cell_tile_data.
neither worked for me, and when I asked on reddit, it was explained to me that I needed to know the layer as part of the function parameter.

So if godot doesn’t have this feature built in (which I personally think would be odd), but if it doesn’t… does someone have any ideas how I can return the layer data?

I’m fairly new to godot and programming, so please have patience. Asking on here is literally my last hope. read and reread the docs, watched the few videos I could find on it…and even asked gpt. XD
Thank you

2 Likes

I really appreciate the time you took for the response. The issue I was having is I’m trying to get the layer data that the tile is on.
So this gives me the position of the tile, but not the layer data. Which is what I am trying to achieve.
So in this case, you assumed in the “get_cell_tile_data(0,v_cell_coords)” the layer we are working with is layer 0. What I need is a way of the user pulling the layer data. Like is the tile they clicked on layer 0 or layer 3?

Gotcha, that is what I sort of figured. Thank you.

Okay, So after a bit (a ton) of messing around, I feel like this SHOULD work…but its not. Saying my “get_layers_count” in base null instance on null instance.
First: what Exactly does that mean? I thought it meant that the instance just doesn’t exist.
Anyways, here is what I have… Thoughts?

func _input(event):
	if Input.is_action_just_pressed("left_mouse_btn"):
		find_filled_cell_layer($tile_map)

func find_filled_cell_layer(tilemap: TileMap) -> int:
	var layer_count = $tile_map.get_layers_count()
	var mouse_gpos = get_global_mouse_position()
	var mouse_lmpos = local_to_map(to_local(mouse_gpos))

	# Iterate through each layer starting from the front
	for layer_index in range(layer_count - 1, -1, -1): 
		var layer_name = $tile_map.get_layer_name(layer_index)
		var cells = $tile_map.get_cell_tile_data(layer_name,Vector2i(mouse_lmpos),false)
		
		# Check each cell in the layer
		for cell in cells:
			var tile_id = $tile_map.get_cell_source_id(layer_index,Vector2i(mouse_lmpos))
			
			# Assuming filled cell has a non-zero tile ID
			if tile_id != 0:
				return layer_index  

	return -1  

I think i am trying to use it how you described.

var layer_count = $tile_map.get_layers_count()

if my tile map has layers 0, 1, 2. Then “get_layer_count()” should return 3. And then assign 3 to my layer_count variable. Is that not correct?

The problem I’m having is: Its returning “in base null instance on null instance”.

If $tile_map.get_layers_count() errors with trying to call function on a null instance it means that $tile_map is null, so it can’t find a node with that node path (get_node("tile_map")) most likely the wrong name or running from a node that isn’t the parent of the tilemap.

Don’t use tilemap.get_cell_tile_data(layer_name, ...) or any of the other methods with the layer name, they all take layer index as the layer parameter. The name is mostly irrelevant.

get_cell_tile_data() doesn’t return a list of cells, it returns a TileData object with the info about that cell.

get_cell_source_id() doesn’t return a tile ID it returns a tile source ID, so all tiles from a single atlas will all have the same ID for instance. if each tile is from a different image (or if only one tile is defined per source, like how the godot 3 to 4 converter sets it up) they will all have different source IDs though.

It will return -1 not 0 for cells that are not set to any tile. but of course cells set to a fully transparent tile will return something other than -1 so be careful with those.

1.This is what is confusing me. The $tile_map is the path I get when I drag my tile map over, and my TileMap IS labeled tile_map, and the the node my script is attached to. :melting_face: So I still dont’ understand why its returning null.

2.This is good to know. I appreciate that

I’m at work and will have to mess around with this more later. Thanks again for the time.

I don’t know why it’s not getting your node, there will most likely be an error in the debug tab whenever you use something like $tile_map and it can’t find the node. that error message will show the full path of the node that it’s looking relative to, so that’s one thing you can check to make sure it’s what you think it is.

So for yours it might be something like Node not found: "tile_map" (relative to "/root/SceneRootHere/SomeOtherNode/ParentOfTilemap")

You can also check the remote scene tab while the game is still running to see the scene tree as it currently is, to make sure the tilemap didn’t get moved or removed or renamed or something.

2 Likes