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\$
  • \$\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
3
\$\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\$
  • \$\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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.