Handling tile map coordinates in addition to world, camera, and screen coordinates

I’m a little unsure as how to “best” handle tile coordinates when trying to implement a tiled map game.

Currently, I have the following 3 spaces set up:

  • Screen space (game window)
  • Camera space (not necessarily the same as screen space; I can put the camera anywhere within the game window, have virtual bounds, etc. I also have zoom and rotate working with my camera.)
  • World space. The problem is that world space is 1:1 with pixels. So if I want to have 2 tiles that have a 32 pixel width next to each other, I have to specify that the tile gets drawn 32 world units adjacent. The same issue applies to game objects. To get a game object at tile coordinates <x, y>, I must scale it by the tile width (32 in this case).

Similarly, I can convert a point/Vector2 from any one of those spaces to another (e.g. mouse coordinates to world coordinates). So far, everything seems to be working great, even after putting the camera view in different spots of the game window and zooming and rotating. In the screenshot, we can see that the gargoyle is at 3,2 in tiled space (note that the tile map begins at <0, 0>, so it’s 4 tiles to the right and 2 tiles down).

public static Point GetTilePositionForWorld(Vector2 worldPosition)
{
    return (worldPosition / 32).ToPoint();
}

One possible solution is, when creating game objects, to simply scale the position in the game object’s class by the tile width. For example, in the constructor for creating a game object I could simply scale the position such that if I I create a new game object with a world position of, say, <5, 2> I can ensure the object gets drawn at <5, 2> in the tiled space. However, I am afraid this is not the right way. Ideally, I want to just specify any world coordinate <x, y> and ensure that it gets drawn in the corresponding <x, y> tile. That is, a 1:1 relationship between world and tile space.

The pixel coordinates only matter when rendering. You can use any scale you’d like internally (for your world space), but you need to rescale when drawing.

In fact, SpriteBatch does just that. It rescales the coordinates so you can pass positions in pixels, because that’s not how the GPU interprets the coordinates.