Forum Media Blog Contact Presskit

Map coordinates #2

2020-02-14

Hello and welcome to part two of our blog post about map coordinates in Nebuchadnezzar. Today we’ll go over the difference between screen space and world space, as well as how they’re converted into each other.

Last post we discussed the map-tile coordinate system—but the coordinates described only represented an internal arrangement and didn’t show outward appearance. So the user can’t tell if the game is using the Staggered or Diamond coordinate system—or a completely different one.

However, what we want from the game is for the player to see where all the tiles should be. Before we can show how it’s done, we have to explain a few concepts.

Screen space

The screen space is the area where the player can see what’s on screen. Object positions in this space are in relation to the screen. Typically, this space has a screen resolution size and its units are pixels.

The origin (zero) lies in the upper left corner. [x] coordinates move to the right. [y] coordinates move to the bottom. This differs from the typical space in mathematics, where the origin tends to be at the bottom left corner and [y] coordinates moves upwards.

Screen and it's coordinates.

World space

World space is the space of all objects in a game that describes their position in the world of a game. From the player’s point of view, it’s irrelevant where this space starts and what coordinate system it uses.

An example would be the position of the place where the main character is standing.

However, whether the player sees the hero depends on the positioning and setting of the world-sensing camera. That’s because the camera determines how the world’s objects are displayed on screen. This transfer between the world and the screen is called projection.

Projection from the game world to the screen.

If we have an isometric game where each object is always on a specific tile or group of tiles, and it’s fixed to this position—the coordinate system of the tiles described in the previous blog post would sufficiently represent the whole game.

But this is not an example of a typical isometric game. Nor is it typical in Nebuchadnezzar. An example being: the movement of walkers moving smoothly from one tile to another. This requires walkers to sometimes be in the middle of a tile and sometimes to be between two tiles.

Therefore in Nebuchadnezzar, as a world space, we must consider not only the individual tiles, but also the absolute position of each object. Yet the space of isometric tiles provides many advantages—above all, legibility and clarity for players.

Because Nebuchadnezzar is a 2D isometric game, the transformation between screen space and world space is relatively simple. The only transformations our camera applies are translations (the world will move around on the player’s screen) and scale (the world is rendered larger or smaller on the player’s screen). What’s a little more complex is figuring out which tiles belong to a given position in the world space.

Of course, Nebuchadnezzar supports rotation, too, but it’s not done at the camera level (as is common in 3D games)—but rather by rotating the entire world space and its coordinates. We’ll have more on this in another blog post.

Examples of translation and scale transformations.

Screen to world

Here’s an example of a situation where we need to convert from screen space to a specific map tile: The player wants to make a building and clicks on a specific location on screen. The game must first determine the cursor’s position in the world coordinates. And so it applies inverted transformations (opposite to those used in rendering) to the cursor’s position in the screen.

This will give us a position in the world space and from here we will then calculate a specific tile of the map. Again, the calculation is more complicated in the Staggered system than in the Diamond system. Now we have a specific tile and we can build the required building on it—but only if all the conditions for construction are met, of course.

Transformation from screen coordinates to tile coordinates.

World to screen

The conversion from world space to screen space is mostly applied in rendering the game, because for the player we need to depict the world as “seen” by the current camera.

We hope you enjoyed the post. Feel free to share any thoughts, ideas or questions.

Below you will again find some samples from our source code related to the operations described. Feel free to try them out in your projects.

Get tile coordinates from world space coordinates.

/**
 * @brief Get tile coordinates from world space coordinates.
 *
 * @param pos Coordinates in word space.
 */
N_Point Tile_Scene::pos2tile(const N_Point pos)
{
  const int base_x = pos.x / TILE_WIDTH;
  const int base_y = (pos.y / TILE_HEIGHT) - (pos.y < 0);
  const int off_x = pos.x - ((base_x * TILE_WIDTH) + TILE_HALF_WIDTH);
  const int off_y = pos.y - ((base_y * TILE_HEIGHT) + TILE_HALF_HEIGHT);

  const bool inside = (std::abs(off_y) != TILE_HALF_HEIGHT) && ((std::abs(off_x) / (TILE_HALF_HEIGHT - std::abs(off_y))) < 2);

  if (inside) {
    return {base_x, base_y * 2};
  }
  else {
    return {base_x - (off_x < 0), (2 * base_y) - 2 * (off_y < 0) + 1};
  }
}

Transformations between screen and world space.

/**
 * @brief Get world space coordinates from screen space coordinates.
 *
 * @param pos Coordinates in screen space.
 */
inline N_Point screen2scene(const N_Point pos) const {
  return {
    (pos.x / scene_zoom_factor_inverted_) + scene_offset_.x, 
    (pos.y / scene_zoom_factor_inverted_) + scene_offset_.y};
}

/**
 * @brief Get screen space coordinates from world space coordinates.
 *
 * @param pos Coordinates in world space.
 */
inline N_Point scene2screen(const N_Point pos) const {
  return {
    (pos.x - scene_offset_.x) * scene_zoom_factor_inverted_, 
    (pos.y - scene_offset_.y) * scene_zoom_factor_inverted_};
}
Discuss this blog post on our forum or reddit.

Add Nebuchadnezzar to wishlist

GO TO STEAM STORE

Recent blog posts

Stay in touch