SFML community forums

Help => General => Topic started by: argh on September 19, 2015, 05:09:42 pm

Title: Collision: Erasing two sprites from two different vectors (Solved)
Post by: argh on September 19, 2015, 05:09:42 pm
Hi everyone,

I have a problem erasing two elements when they collide. I go thru the 2 vectors of sprites and check if they have intersected with each other, if true, then I erase the two elements from the two vectors (bullets & enemies).

My problem is the following: I can erase one, but how can I erase the second one?

That is how the function looks like so far.
void collision()
  {
          for (auto e = enemies.begin(); e != enemies.end(); e++)
          {
                  for (auto i = bullets.begin(); i != bullets.end(); i++)
                  {
                          sf::FloatRect enemiez = e->getGlobalBounds();
                          sf::FloatRect bulletz = i->getGlobalBounds();

                          if (bulletz.intersects(enemiez))
                          {
                                bullets.erase(i);
              //enemies.erase(e); <-- if i uncomment this line i get a "vector iterator not incrementable!" exception.
                                break;
                          }
                  }
          }
  }
 


I understand that it is a problem with the size and the index in the vector and erasing won't work in the same iteration of the loop. I tried also to erase the enemies(e) in the outer loop, but no good.

I have no idea how else I can solve this? Should I try a totally different approach or am I on the right track?

Thank you for your help in advance!
PS This is my first project with SFML (newest version of SFML and Visual Studio 2013).
Title: Re: Collision: Erasing two sprites from two different vectors
Post by: zsbzsb on September 19, 2015, 05:25:27 pm
Reading the documentation of vector::erase (http://www.cplusplus.com/reference/vector/vector/erase/) always helps.

Quote from: http://www.cplusplus.com/reference/vector/vector/erase/
Return value: An iterator pointing to the new location of the element that followed the last element erased by the function call.

So in the context of your code...

void collision()
  {
      for (auto e = enemies.begin(); e != enemies.end(); /* don't increment here */ )
      {
          bool collides = false;

          for (auto i = bullets.begin(); i != bullets.end(); i++)
          {
              sf::FloatRect enemiez = e->getGlobalBounds();
              sf::FloatRect bulletz = i->getGlobalBounds();

              if (bulletz.intersects(enemiez))
              {
                bullets.erase(i);

                // assign the return value and set the flag that a collision happened
                e = enemies.erase(e);
                collides = true;

                break;
              }
          }

          // only increment if no collision happened
          if (!collides)
            e++;
      }
  }

Notice how I assigned your iterator to the return value of erase()? This is because once you erase an element your previous iterator is invalidated. Also I added a boolean so if you remove an element you don't increment the iterator and skip the collision check for the next element.
Title: Re: Collision: Erasing two sprites from two different vectors
Post by: argh on September 19, 2015, 05:48:41 pm
Yes and ty it helped a lot. It works as intended and also helped me correct another function 8)