# Using 2D std::vector for map and collision

Hello to anyone reading this. I am having trouble on how to use std::vector. From what I know, std::vector is a flexible version of an array and iterator is used to go through each individual element within a vector.

std::vector<std::vector<int>> row;
std::vector<int> column;
//This is equivalent to... (?)
int array[i][j];


So what if I wanted to use a 2D std::vector for a tilemap?

std::vector<std::vector<int>> row;
std::vector<int> column;

for (int i = 0; i < row.size(); ++i) {
for (int j = 0; j < row[i].size(); ++j) {
//something with map
}
}

for (itr = row.begin; != row.end(); ++itr) {
//something with each block of the map?
}


Sorry if the code is incomplete or wrong. I can't seem to understand the standard format of std::vector and using an iterator.

Thank you to those willing to help.

• VTCers: "getting started" is traditionally in reference to users that ask "how do I start" or "what engine should I use". Yes, it seems that this user may be getting started, but they have a legitimate question. They are not simply asking us to give them the broad introduction to game development, and have given a very specific and answerable question. – Gnemlock Oct 10 '17 at 7:01

The 'equivalent' of a 2d array for a vector of vector is something like this:

std::vector<std::vector<int>> mTileMap;


You can add values to it like this:

int numRows = 4;
int numCols = 6;

for ( int y = 0; y < numRows; ++y ){
mTileMap.push_back( std::vector<int>() );
for ( int x = 0; x < numCols; ++x ){
}
}


You can use that method if all the values for the map are different.

A simpler way to only allocate your map would be to tell it the sizes at construction:

int defaultTileValue = 0;

std::vector<std::vector<int>> mTileMap( numRows,
std::vector<int>( numCols, defaultTileValue ) );


or

mTileMap = std::vector<std::vector<int>>( numRows,
std::vector<int>( numCols, defaultTileValue ) );


With that method, you lose the possibility to set a specific value for each tile. You can use the iteration methods described below to do that.

And you access it this way:

for ( int y = 0; y < mTileMap.size(); ++y ) {
for ( int x = 0; x < mTileMap[y].size(); ++x ) {
std::cout <<
"TileMap value at row " << y <<
" column " << x <<
" is " << mTileMap[y][x] << "\n";
}
}


If you want to use iterators, you can get go through each element like this:

for ( auto& itRow : mTileMap  )
{
for ( auto& itCol : itRow )
{
std::cout << "TileMap value is " << itCol << "\n";
}
}


The iterator version allows you to go through each element, but you lose the concept of 'index' for your x and y. It's ok for some situations, but for some other situations, an iterator won't do and you'll have to use the first version.

Note that the above is a very naive way to create and use a 2d vector. It works and it is easy to understand, but it's not very efficient, specially if the data is to be used and iterated over often.

You might be interested in a single vector that contains all your data.

// In header
const int numRows = 4;
const int numCols = 6;

int getFlatVectorIndex( int aIndexX, int aIndexY ) { return ( numCols * aIndexY ) + aIndexX;}

std::vector<int> mTileMap;

// This is the initialization code:
mTileMap.resize( numRows * numCols );

for ( int y = 0; y < numRows; ++y ){
for ( int x = 0; x < numCols; ++x ){
mTileMap[getFlatVectorIndex( x, y )] = /* your tile will be set or accessed here */;
}
}


The reason why this implementation is better is because all your data are close together in memory, allowing you to benefit from Data Locality.

Disclaimer: I don't have access to my compiler to make sure this works for now.

• I very much appreciate your response. I did see somewhere about using just a single std::vector rather than 2D std::vector before. But I wasn't exactly sure about the approach of using std::vector in general. – NullFrag Oct 6 '17 at 21:08
• @NullFrag A std::vector is a bit like an array on steroids. – Vaillancourt Oct 6 '17 at 21:16
• @NullFrag Does that answer your question? – Vaillancourt Oct 7 '17 at 15:35
• Yes, my bad. I don't use this site much. – NullFrag Oct 7 '17 at 18:39
• Correct, but somewhat suboptimal and outdated. E.g. to iterate over all tiles we'd now write for (auto& row : mTileMap) { for (auto& tile : row) { ... . And creating the 6x4 empty map can be done by the constructor of mTileMap, instead of two nested loops. – MSalters Oct 26 '17 at 13:40