-
I am having trouble accessing a one-dimensional vector as a multi-dimensional one.
I have a MultiArray template class, and it is accessed using the function operator. It accesses elements through the expression row * m_columns + col. The row and col are the two inputs to the operator while the m_columns is the width/number of columns in the array. There is also a version that accesses the array with one number. Its underlying representation is a one-dimensional vector.
The problem is when I try to load a level:
void Map::LoadFromFile(const std::string& filename)
{
std::ifstream map_file(filename);
std::cout << m_map.GetHeight() << ", " << m_map.GetWidth() << std::endl;
std::cout << m_map_dimensions.y << ", " << m_map_dimensions.x << std::endl;
if(map_file.is_open())
{
for(unsigned int i = 0; i < m_map_dimensions.y; i++)
{
for(unsigned int j = 0; j < m_map_dimensions.x; j++)
{
int current_tile;
map_file >> current_tile;
try
{
m_map(i, j) = current_tile;
}
catch(std::exception& e)
{
std::cerr << "Vector overflow in map loading." << std::endl;
exit(EXIT_FAILURE);
}
}
}
}
else
std::cerr << "Couldn't load map file: " << filename << "." << std::endl;
}
(The m_map is a MultiArray<int> and the m_map_dimensions an sf::Vector2u)
The dimensions of the level are 20 * 15 (screen dimensions divided by height dimensions), so I made a map file that looks like this:
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
but it loads it skewed and only ever accesses up to element 229 in the MultiArray.
This is how it loads the file:
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
The graphical output code is outputting this messed-up array in the graphical representation of this using a spritesheet, so I know it is working correctly.
-
Check the stream validity after the input operator, for example as follows:
int current_tile;
while (map_file >> current_tile)
{
// compute indices, or directly store to 1D vector
}
Why doesn't your code load the dimensions of the map? Are they constant?
And does your MultiArray class work correctly? Is the input correct if you load it directly into a std::vector?
-
I tried changing my code to use a normal vector but is still giving me messed up output. This is my new code:
int current_tile, i = 0, j = 0;
while(map_file >> current_tile)
{
try
{
//m_map.at(i * m_map_dimensions.y + j) = current_tile;
m_map.push_back(current_tile);
}
catch(std::exception& e)
{
std::cerr << "Vector overflow in map loading. Error: " << e.what() << std::endl;
}
if(j < m_map_dimensions.y)
j++;
else
{
j = 0;
if(i < m_map_dimensions.x)
i++;
else
i = 0;
}
}
I also did a comparison between my MultiArray and a normal vector and they both worked the same (with MultiArray's one and two parameter access operator).
-
I've gone back to my original code as it gets me closest to what I intend to do, but I did add a check to see if the input operation succeeds. And by modifying my map file I discovered that it is loading the 16th-20th tiles as the first few tiles of the next line.
-
I have now determined that it isn't my loading code that is messing up, but my drawing code. I used the debugger and saw that it was putting the correct numbers in the correct spot in the array. I also added some debugging output to the loops to confirm this. Now here's my drawing code:
void Map::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
sf::Sprite current_sprite;
static int once_flag = 0;
if(!once_flag)
{
std::cout << m_map.GetHeight() << ", " << m_map.GetWidth() << std::endl;
std::cout << m_map_dimensions.x << ", " << m_map_dimensions.y << std::endl;
for(unsigned int i = 0; i < m_map_dimensions.y; i++)
{
for(unsigned int j = 0; j < m_map_dimensions.x; j++)
{
std::cout << m_map(i, j) << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
once_flag = 1;
}
for(unsigned int i = 0; i < m_map_dimensions.y; i++)
{
for(unsigned int j = 0; j < m_map_dimensions.x; j++)
{
try
{
current_sprite.setTexture(m_spritesheet.GetTexture());
current_sprite.setTextureRect(m_spritesheet.GetRect(m_map(i, j)));
current_sprite.setPosition(j * m_tile_dimensions.x, i * m_tile_dimensions.y);
target.draw(current_sprite, states);
}
catch(std::exception& e)
{
std::cerr << "Vector overflow in map drawing. Error: " << e.what() << std::endl;
}
}
}
}
As far as I can see, the loops are the same as the loading loop, but they both produce the same output, which is the skewed version of the map.