Hello and welcome to another blog post about the development of Nebuchadnezzar. This time we will look at the core of almost every isometric game: the map. Specifically, well go over two different map coordinate systems and show you the one we use.
Typically, isometric games take place on a tile map. There are two basic coordinate systems for these maps: Staggered or Diamond. Games usually use one or the other. We use Staggered in Nebuchadnezzar. Although it looks complicated at first sight, we have several good reasons for choosing this system.
Lets take a look.
From the beginning of Nebuchadnezzars development, we knew we wanted the maps to have a rectangular shape because its much more immersive. If all tiles are in range (0 - [map width], 0 - [map height]) then the Staggered map system retains a rectangular shape where as a Diamond map would have a rhomboid shape, and therefore, wouldnt fit the whole screen.
If all tiles are in this range, then we can store them all in the matrix data structure. This provides fast access to arbitrary tiles. This is very advantageousmainly during rendering, when in each frame we need to iterate over many tiles.
Its connected with another big advantage. Because rendering is one of the most compute consuming parts of a game, we only want to render whats necessary. This typically means: only the tiles visible on a players screen. In the Staggered systems rectangular cutout of the screen, all the tiles will be in range ([x1] - [x2], [y1] - [y2]). Thanks to this, we can exclusively iterate over this sub-matrix of tiles. Notice the diagram of the Diamond systemthere isnt a simple way to describe its range.
Of course, this system has disadvantages too. Mainly, its ineffective at interpreting coordinates. This is a problem, for example, when moving objects. If we want to move in the four main directions, the Diamond system makes computation of neighboring tiles very simple. Just add or subtract 1 in the [x] or [y] axis. This gives us all four directions. In the Staggered system, its more complicated, and also the formula differs for odd and even rows.
In general, most of the operations in the Staggered system are more complicated. Another example being the distances between two tiles (with limitation to the four main directions) or even the rotation of the whole system, which in itself can be a separate blog post. In the end, we have transformation functions between the Staggered and Diamond systems. And for more complicated operations, we may use the more convenient one.
With ongoing developments, theres a growing number of coordinate operations we need. Although none of the operations are complex, it can be difficult to invent and test them. Under the text, you will find snippets of our source code with some of coordinate operations. You can use the code in your own project or to test your spatial orientation.
Next time, well look at another type of coordinate system as well as other operations. For example, an important element is the transformation between screen space and game space. We hope you learned something new about isometric games in this post. Feel free to ask any questions about this topic or any other.
See you soon!
And as always, you can also read and discuss this blog post on our websites, forum or reddit.
/**
* @brief Get neighbor tile in the given direction.
*
* @param pos Cooridinates of origin tile.
* @param direction Neighbor direction in range <0, 7> for NE, E, SE, S, SW, W, NW, N.
*/
N_Point Tile_Scene::neighbor(const N_Point pos, const int direction) {
const int x = pos.x;
const int y = pos.y;
switch (direction) {
case 0:
return {x + std::abs(y % 2), y - 1};
case 2:
return {x + std::abs(y % 2), y + 1};
case 4:
return {x - std::abs((y + 1) % 2), y + 1};
case 6:
return {x - std::abs((y + 1) % 2), y - 1};
case 1:
return {x + 1, y};
case 3:
return {x, y + 2};
case 5:
return {x - 1, y};
case 7:
return {x, y - 2};
}
n_assert_msg("Invalid parameters.");
return N_Point();
}
/**
* @brief Get direction between two neighboring tiles.
*
* @param from Cooridinates of origin tile.
* @param to Cooridinates of destination tile.
*
* @return Direction in range <0, 7> for NE, E, SE, S, SW, W, NW, N.
*/
int Tile_Scene::direction(const N_Point from, const N_Point to)
{
const int x = to.x - from.x;
const int y = to.y - from.y;
if ((x == std::abs(from.y % 2)) && (y == -1)) {
return 0;
}
else if ((x == std::abs(from.y % 2)) && (y == 1)) {
return 2;
}
else if ((x == -std::abs((from.y + 1) % 2)) && (y == 1)) {
return 4;
}
else if ((x == -std::abs((from.y + 1) % 2)) && (y == -1)) {
return 6;
}
else if ((x == 1) && (y == 0)) {
return 1;
}
else if ((x == 0) && (y == 2)) {
return 3;
}
else if ((x == -1) && (y == 0)) {
return 5;
}
else if ((x == 0) && (y == -2)) {
return 7;
}
n_assert_msg("Invalid parameters.");
return 0;
}
/**
* @brief Get diamond coordinates for given staggered coordinates.
*
* @param pos Staggered coordinates.
*/
N_Point Tile_Scene::to_diamond(const N_Point pos)
{
return {((pos.y + 1) / 2) + pos.x + (((pos.y + 1) % 2) * (pos.y < 0)), (pos.y / 2) - pos.x + ((pos.y % 2) * (pos.y < 0))};
}
/**
* @brief Get staggered coordinates for given diamond coordinates.
*
* @param pos Diamond coordinates.
*/
N_Point Tile_Scene::from_diamond(const N_Point pos)
{
if (pos.x % 2) {
return {(pos.x / 2) - ((pos.y - (pos.y < 0)) / 2) + ((pos.x % 2) * (pos.x < 0)), pos.x + pos.y};
}
else {
return {(pos.x / 2) - ((pos.y + (pos.y > 0)) / 2) + ((pos.x % 2) * (pos.x < 0)), pos.x + pos.y};
}
}
[ 2020-01-31 15:19:48 CET ] [ Original post ]
- Linux Depot [24.74 M]
Gameplay
From plowing fields to creating products, players must oversee the manufacturing of agriculture and goods for the city population. Players have an arsenal of tools to optimize their objectives. In addition, a maximum overview of their city helps players to solve problems and prevent population loss. Nebuchadnezzar’s gameplay is geared towards all types of players: from beginners of the genre to experienced strategists.Campaign
Nebuchadnezzar’s main campaign contains 16 historical missions covering the colonization of ancient lands to the conquest of Babylon by Persians in 6th Century BC. Each mission summons a different time period in Ancient Mesopotamian history. Players must carry out tasks important to the specific time and place of each mission, including the construction of historical monuments.Monuments
During the campaign players will not only build complex ancient monuments, but design them too. Nebuchadnezzar features an in-game “monument editor” giving players complete control over their buildings. From structural design to color scheme to final details: it’s in the hands of the player. Will you recreate history or make history? It’s up to you.Mods & Localization
Nebuchadnezzar was created with mods and localization in mind. Modders will be able to create their own buildings, goods, and monuments. And in addition, they can invent new missions and campaigns. All definition files are written in the easy to read Lua language. Localizing mods will not be a problem. You can create mods in multiple languages and/or add languages to existing ones. This applies to the base game as well.- OS: TBA
- Processor: TBA
- Graphics: TBA
- OS: TBA
- Processor: TBA
- Graphics: TBA
[ 6107 ]
[ 1061 ]