What are the 2D coordinate systems?

Godot Version



What are the 2D coordinate systems?

The docs mention 9 (absolute screen, screen, absolute embedder, embedder, camera, viewport, canvas, parent item, item). Confusingly, several common APIs use (get_global_mouse_position) and transform (local_to_map) coordinate systems that are none of those. The docs for those methods are no help (“Returns the map coordinates of the cell containing the given local position”). It also looks like they arbitrarily changed the name of some methods (world_to_map became local_to_map, which sounds completely different but apparently is the same?).

If i’m understanding the docs correctly (which i doubt), Canvas, Global and Local are all the same thing. Screen and Absolute Embedder might be the same thing. get_global_mouse_position is a Canvas position but get_mouse_position is a Screen position. Canvas and Screen are different things. Screen and Viewport are different things. i can’t find any reference for map (as in local_to_map) but if i had to guess i’d say it’s which tile you’re looking at in a TileMap.

i began wanting to know which tile a player is standing on (converting the player transform position to a position on the tile map) and ended up going down this rabbit hole of global local screen canvas things and now my brain hurts.

Would someone be willing to explain these in human language and which ones i should care about?

You should focus on Global, Local, and tile maps as that is what you are using.

For 2D global should be the outermost coordinate system, in the editor global 0,0 is where the X and Y axis lines join. Local is relative to any parent’s coordinates, almost exclusively used with sibling-to-sibling calculations.

Tilemaps might assume your player is a child, therefor in it’s Local space. In that case using

# tilemap script
var player_tile_index := self.local_to_map($Player.position)

will retrieve the 2d tile index for where the player is, this can be used for other tilemap functions like get_cell_tile_data, set_cell, and erase_cell.

If the player is not a child of the tilemap then convertion is needed, from global to tilemap’s Local

# tilemap script
var player_local_position := self.to_local(player.global_position)
var player_tiler_index := self.local_to_map(player_local_position)
1 Like

Doing some experiments… Huh. It looks like global and local return the exact same value. That’s unexpected.

If local is the coordinate system of a CanvasItem (which i’ve just learned all Node2Ds are) it should be different than global, which is the outermost thing (meaning the game window, not the monitor). Unless… i guess TileMaps are always full screen so for TileMaps specifically, global and local really are the same. i tried to_local() for the player over a different type of object and local and global didn’t match. Neat. i learned something new.

It’s not that tilemaps are fullscreen. Global will be the same as Local if the parent has no transformations, scale at 1,1 position at 0,0 rotation 0; Chances are your Tilemap is not offset from global 0,0 so the Local coordinates will not be offset either.

A majority of nodes do spend their lifetime at 0,0 so their children are not offset either and happen to share global coordinate space.

Huh. i absolutely didn’t know that but it makes sense. i tried adding tiles offscreen and the local coords didn’t change and i didn’t understand why. The position, scale and rotation weren’t changed so it matches what you’re describing. If i relied on it to always be local then in the future when i modified the transform my code would have failed and i would have been confused so this is good to know.

The tilemap’s position is only affected by the move tool, same with scaling and rotation. It’s tiles are only data. Maybe you are use to the sprite/collision’s behavior of keeping centered, some nodes like the Tilemap, Polygon2D, and most 3D nodes do not center themselves and hold a psuedo-offset due to their data being set away from 0,0. Similar to a Sprite’s texture with a lot of extra transparent pixels on one side, it creates a offset within the data, rather than the transform.