I'm writing a game using SFML and C++11 features, such as the range loop. When working on tile maps, I basically made a class for each map tile, a light-weight class that simply contains its sprite, position, and such, and then built some nested vectors to represent the game map layers.
In order to optimize the process of drawing thousands of objects on the screen at a time, I was simply drawing what the player sees. This went well.
I have the following method that renders the game map, the condition basically returns true if the tile position is within the camera boundaries
void gameMap::render(sf::RenderWindow &winMain, sf::Vector2f offset) {
for(vector<int> vec1 : backgroundData)
for(int i : vec1)
if(collides(i.pos, offset)
myWindow.draw(i.sprite);
}
it works fine, however in-game I am getting 30 FPS roughly, and a lot of rough movement. But what surprises me is that the code bellow does the same thing, renders the same amount of tile sprites, but runs at 65 fps and the movement is perfectly smooth
void gameMap::render(sf::RenderWindow &winMain, sf::Vector2f offset) {
for(int i = 0; i < backgroundTiles.size(); i++)
for(int j = 0; j < backgroundTiles[i].size(); j++)
if(collides(backgroundTiles[i][j].pos, offset)
myWindow.draw(backgroundTiles[i][j].sprite);
}
Why is this happening? Is the C++11 range-based loop so much slower than the old school for? I really want to hear an answer to this, because my eyes honestly prefer the range based loop, and I'd hate to find out that the range based loop is twice as slow.
The outer loop is making a copy of each vector contained in backgroundData
:
for(vector<int> vec1 : backgroundData)
Change that to either of the following:
for(vector<int>& vec1 : backgroundData)
for(const vector<int>& vec1 : backgroundData)
This will make vec1
into a reference to the vector as opposed to a copy. Since vectors are expensive to copy, while references are cheap to use, this will significantly improve performance.
As to the choice between non-const
and const
reference, I'd use the latter whenever I can.
A more general alternative is to write
for(auto&& vec1 : backgroundData)
This creates an automatically-typed reference vec1
to whatever type backgroundData
contains. &&
in this context ends up making vec1
bind to any of: rvalue reference, reference or const
reference, depending on the types that backgroundData
returns. [Hat tip to @Yakk for providing this recommendation]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With