Same TileMapLayer.map_to_local coordinates putting different nodes in different places?

Godot Version

4.5.1.stable.official

Question

I’m brand-new to Godot. I’ve been trying to place hexes under sprites to indicate populated cells. Using to_local, local_to_map, and map_to_local, I’ve been able to achieve a “cursor highlight” for cells (light hex) and sprite placement, but when I try to add a darker hex drawing on the same grid cell as the token, it appears in a drastically different place.

Originally, I was trying to handle this “token area marker” in its own node, but to debug I’ve combined it with the sprite-placing code, thinking that perhaps I was somehow getting different “local” results from map_to_local. Even when I use the same exact coordinates, the dark hex goes in a different place!

Here’s a simplified version of the code:

func _on_grid_context_menu_submenu_id_pressed(id: int) -> void:
	var global_pos = Main.last_right_click_pos
	var hex_pos = Grid.local_to_map(global_pos)
    var local_pos = Grid.map_to_local(hex_pos)

	var token = Token.instantiate()
	var texture = TokenPicker.get_item_icon(id)
	token.texture = texture
    local_pos = Grid.map_to_local(hex_pos)
	token.position = local_pos
	add_child(token)

	var marker = HexScene.instantiate()
	marker.position = local_pos
	marker.color = Color(0, 0, 0, 0.2)
	add_child(marker)

I’m using very similar logic to place a highlighted token at mouse coordinates from within the TileMapLayer script, and that works great:

var hover_marker

func _ready():
	hover_marker = HexScene.instantiate()
	add_child(hover_marker)
	move_child(hover_marker, 0)

func _unhandled_input(event):
	if event is InputEventMouseMotion:
		var pos = event.position
		hover_marker.position = map_to_local(local_to_map(pos))

Why won’t the dark hexes appear where they should? What am I missing here?

It’s local_to_map(), not global_to_map(). The argument needs to be in tile maps’s local space, not in global space. If tile map node’s transforms are non-identity, you first need to convert global position to local position using Node2D::to_local().

Similarly, if you want to get a global position, you need to convert what is returned by map_to_local() using Node2D::to_global()

1 Like

The issue has been identified – and the offending code wasn’t included above.
In the HexScene script itself, I was using self.position as the “center” when I should have been using (0,0). I was placing the hex at position and also centering it at position relative to itself, doubling the center’s distance from where it was intended to go.

Replacing position with Vector2(0,0) fixed the problem! Credit to WideFrog, Haledire, Domin0e, and blackshift on the Godot Discord for helping me with this issue.

Thanks! I had to_local originally, and someone suggested removing that as a troubleshooting step. It didn’t make a difference – this happens to work because everything has an origin of (0,0). I’ll restore to_local asap!