Logic of iterating through a list. Element "flickering"
[SOLVED]: Applying proper list iteration procedure fixed problem. (Shown below)
I currently have 开发者_如何转开发a program in which elements of a list are iterated through and erased if they meet certain conditions. Due to the nature of the program, this can be visually seen.
Objects on screen that are being iterated through sometimes flicker on and off. This usually happens when objects around them are destroyed (i.e. erased in the code). At first I thought it was screen flickering, but now I realize that I think my iteration functions' logic may be causing the problem.
Here are the two functions. The first detects bullet collisions with blocks. If a bullet hits a block, the block is destroyed.
// Edit: WRONG WAY TO ITERATE THROUGH LIST
void DetectBulletCollisions()
{
std::list<Bullet>::iterator bullet = game::player_bullets.begin();
for ( ; bullet != game::player_bullets.end(); ++bullet)
{
if (bullet->IsOnScreen())
{
bullet->DetectBlockCollision(game::blocks);
}
else // Remove bullet from list
{
bullet = --game::player_bullets.erase(bullet);
}
}
}
This function moves the blocks that are flickering.
// Edit: RIGHT WAY TO ITERATE THROUGH LIST
void MoveBlocks(const int delta_ticks)
{
// Blocks on screen
std::list<Block>::iterator block = game::blocks.begin();
while (block != game::blocks.end()) // Loop through blocks
{
block->Show(); // Show block
if (!block->IsDestroyed()) // If block hasn't been destroyed
{
block->Move(delta_ticks); // Move block
++block; // Increment iterator
}
else // Block has been destroyed, remove it from list.
{
block = game::blocks.erase(block);
}
}
}
Is there something wrong with the logic of these loops? Notably the second one? It seems that when a block is destroyed, others around it flicker on and off (it isn't consistent, but that may just be frame rate). I'm not sure if the list rearranging the elements after each erasure would be a problem or not. The blocks each have coordinates, so it doesn't matter where they are in the list.
If any more information is needed I'd be happy to give it. I'm just wondering if my logic is wrong in the writing of these loops, or if I should take a different approach. I chose lists because they are the most efficient STL container for removing elements.
In both loops, when you erase an element, you assign the return value of erase
to the loop iterator. According to cplusplus.com, list::erase
returns the element after the erased element. So that code will always skip a bullet or a block when an erase happens if I'm not mistaken. Could that have anything to do with it?
Couldn't you use the double-buffering technique where you work on a background buffer for all these operations and once it is done you swap it out with the current front one so all the changes are done at once which would remove these flickers while you go through the list.
Your solution is still wrong. What if you erase the first item? You are not allowed to decrement the iterator to the beginning of a container.
A typical "erase while iterating" loop looks like this:
void DetectBulletCollisions()
{
std::list<Bullet>::iterator bullet = game::player_bullets.begin();
while (bullet != game::player_bullets.end()) //NB! No incrementing here
{
if (bullet->IsOnScreen())
{
bullet->DetectBlockCollision(game::blocks);
++bullet; //Only increment if not erased
}
else // Remove bullet from list
{
bullet = game::player_bullets.erase(bullet); //iterator "incremented" by erase
}
}
}
精彩评论