0

I want to store a list of tiles (pointers to objects of class "Sprite") in a two dimensional vector.

Currently I'm storing all the sprites of my tilemap in a vector.

std::vector<Sprite*> _tiles;

Now I need to get all the neighbored tiles and I thought it be easier, to store my sprites in a 2d matrix (vector in vector) to do those caluclations.

But I can't figure out how to do that.

Header:

private:
  std::vector<std::vector<Sprite*>> matrix;

C++ File:

vectorMatrix::vectorMatrix(int columns, int rows) { }

vectorMatrix::~vectorMatrix() { } 


void vectorMatrix::addCellAt(int x, int y, Sprite* sprite) {
  std::vector< std::vector<Sprite*> > matrix;
  matrix[x][y].push_back(sprite);
}

But I get an error message if I use two index operators.

bcr
  • 950
  • 8
  • 28
Lisa
  • 111
  • 1
  • 6
  • `matrix[x][y]` gives you a `Sprite *`. You should probably assign to it using `=` instead, and switch to using `std::shared_ptr` to avoid memory leaks from not freeing the data. – hnefatl Apr 28 '18 at 17:10
  • You have not allocated spaces for the matrix – gchen Apr 28 '18 at 17:11

3 Answers3

1

Three problems:

  1. You declare a local variable matrix inside the function, which shadows the member variable.
  2. If the size of the vectors is not set to include the x and y indexes then you will go out of bounds.
  3. matrix[x][y] is not itself a vector, it's an element that you can assign directly:

    matrix[x][y] = sprite;
    

    Remember to consider problem 2 before doing this.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

Why do you think it's a good idea to make your matrix a vector-of-vectors? True, this will "work" in the sense that vec_of_vec_matrix[i][j] will return the right thing, but it's somewhat cumbersome and inefficient.

Instead, consider basing your class on a single vector - of all data, as done in this answer (and probably in many libraries). Element access will be something like (for column-major data):

Sprite*& Matrix::operator()(size_t i, size_t j)
{
    return mData[i * num_columns + j];
}

You could even arrange with map[x][y] to work, using a row proxy class.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Thank you! I found this approach in a lot of examples, that's why i wanted to use it. i don't think it's too cumbersome, but if there's a more performant approach, i'll have a look. Is the performance difference significant? think i'll call a few operations on that tilematrix each frame, so that'd be nice to consider. – Lisa Apr 28 '18 at 18:16
  • @Chris: It will very likely be perform better because element access will not require double-indirection, i.e. you'll only have one memory load, while the multiply+add is well catered for by CPUs. – einpoklum Apr 28 '18 at 18:19
1
std::vector< std::vector<Sprite*> > matrix;

This is an empty std::vector of of std::vector, and as others have pointed out, it's no longer the data member matrix.

Since it's empty, it's not possible to do matrix[0] - get the first row, matrix[1] - get the second row... You can however allocate the size of the matrix in your constructor first -- e.g. This will give you a rows*columns matrix

vectorMatrix::vectorMatrix(int columns, int rows) 
  : matrix(rows, std::vector<Sprite*>(columns))
{
}

And then you can set the xth and yth element to the corresponding Sprite*, and of course x and y should be smaller than rows and columns

matrix[x][y] = sprite;

And don't declare matrix again inside the addCellAt, You can use the data members directly anywhere inside the class.

gchen
  • 1,173
  • 1
  • 7
  • 12