pbivens67 said:
can you explain the following To place tiles just multiply the tile_width/height with the index (and then convert cartesian to isometric).
Lets go through different variants of storing a W * H sized regular grid in memory, and how to index a cell (or tile) from given grid coordinates (X,Y) to set it to 1.
I'll also comment on downsides of the variants.
Most intuitive is maybe to use a 2D array:
int grid[H][W];
grid[Y][X] = 1;
However, using 2D arrays is not recommended for performance reasons. (Although i'm not sure this concern is still upright with modern compilers, i never use 2D arrays at all)
So we usually use a 1D array and care about indexing math ourselves:
int grid[W*H];
grid[Y*W + X] = 1; // we multiply Y with the width of the grid to address a vertical row of cells, and then add X to adress the proper cell within that row
Basically we replace 2D indices with a multiplication and addition, which is still simple to use and becomes second nature quickly.
If your grid is large like games tend to be, we need to allocate the memory on the heap, because if done like above it may eat too much from our stack memory, which could even crash the application:
int *grid = new int [W*H]; // allocate
if (!grid) PanicAndExit(); // if pointer is zero, allocation has failed and we might need to close the app
grid[Y*W + X] = 1; // otherwise work as usual
delete [] grid; // we delete the memory when we no longer need it, eventually before closing the app or if the level has been finished and we want a new one
That's all fine.
But we can eventually use a std::vector instead, making some things easier.
So let's go through the same variants using std::vector…
std::vector< std::vector<int> > grid; // we nest two vectors to get two dimensions. at this point no memory has been allocated yet
grid.resize(H); // now we have allocated H rows, but each row is still empty
for (int y=0; y<H; y++) grid[y].resize(W); // we set the size of each row to W
grid[Y][X] = 1; // finally indexing the grid works the same as with 2D arrays
You see that's not only more complicated, it's also inefficient.
The problem is that now each row is it's own allocation, so the rows may be fragmented across memory. Looping over a region of our grid spanning multiple rows will have to jump around in memory, causing more cache misses than needed.
This problem also persists if we use different code a s shown above:
vector<vector<int>> vect
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
Looks elegant, but still the same problem under the hood.
In our case each row has the same size, so there is no reason to use nested vectors. It's simply bad practice and inefficient.
The only reason we might want to do this is when our rows would have different sizes, e.g. if we used some sparse grid.
Now let's look at using the 1D approach with std::vector:
{
std::vector<int> grid(W*H);
grid[Y*W + X] = 1;
}
// here the grid went out of scope, so the memory will be released automatically in the destructor of our std::vector
No problem here, technically equivalent to the 1D array, and we do not even need to worry about deallocation, which is done automatically for us.
Conclusion:
You should to use either 1D array or 1D std::vector, but 2D or nested variants only if you have a really good reason to so. For a regular grid there is no such reason, so use 1D and handle indexing math yourself.
If the latter feels cumbersome, use a class to manage memory allocation and provide tooling functions to implement the indexing math.
E.g.:
struct TileMap
{
std::vector<int> grid;
int W,H;
void Allocate (int w, int h)
{
W=w; H=h; grid.resize(W*H);
}
int TileIndex (int x, int y)
{
return y*W + x;
}
void SetTile (int x, int y, int value)
{
grid[TileIndex(x,y)] = value;
}
int GetTile (int x, int y)
{
return grid[TileIndex(x,y)];
}
};
Because grid indexing math is so simple, i'm not sure if that's needed. A matter of taste, but it's an example of using data structures to write code once and use many times.
When working with 3D grids, i do use such things. But for 2D grids i usually just write the indexing math in place.