0
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ 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. \$\endgroup\$
    – Gnemlock
    Oct 10 '17 at 7:01
2
\$\begingroup\$

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 ){
    mTileMap[y].push_back( /* your tile will be added here*/ );
  }
}

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.

\$\endgroup\$
6
  • \$\begingroup\$ 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. \$\endgroup\$
    – NullFrag
    Oct 6 '17 at 21:08
  • \$\begingroup\$ @NullFrag A std::vector is a bit like an array on steroids. \$\endgroup\$
    – Vaillancourt
    Oct 6 '17 at 21:16
  • \$\begingroup\$ @NullFrag Does that answer your question? \$\endgroup\$
    – Vaillancourt
    Oct 7 '17 at 15:35
  • \$\begingroup\$ Yes, my bad. I don't use this site much. \$\endgroup\$
    – NullFrag
    Oct 7 '17 at 18:39
  • \$\begingroup\$ 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. \$\endgroup\$
    – MSalters
    Oct 26 '17 at 13:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .