Hi,
I have a player and when he intersects with the door, the door should erase, but the player still erase all doors, how can i fix it that he only erase the door he intersects, here is my code:
RectangleShape door;
std::vector<RectangleShape> doors(3u);
....
(auto& door: doors){
FloatRect playerBounds = player.getGlobalBounds();
FloatRect doorBounds = door.getGlobalBounds();
for(int i = 0; i < doors.size(); i++){
if(doorBounds.intersects(playerBounds)){
doors.erase(doors.begin(), doors.end());
}
}
window.draw(doors[1]);
window.draw(doors[2]);
}
As exploiter says, erasing mid-iteration is not a good idea. Instead consider std::remove_if (https://en.cppreference.com/w/cpp/algorithm/remove).
doors.erase(std::remove_if(doors.begin(), doors.end(), Predicate(const Door&)), doors.end());
Predicate is a functor, std::function, function pointer or lambda that returns true on a condition when an element should be removed. Each element in your vector is automatically passed to it as a parameter. In your case you can use a lambda to decide if the door collides
[playerBounds](const Door& door)
{
return playerBounds.intersects(door.getGlobalBounds());
}
The remove thing dont work i try this, but still booth doors gone,
RectangleShape door;
std::vector<RectangleShape> doors(3);
std::vector<RectangleShape>::iterator it;
...
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event));
...
for (int j = 0; j < doors.size(); j++){
doors[j].setFillColor(Color::Cyan);
doors[1].setSize(Vector2f(100, 100));
doors[1].setPosition(Vector2f(650, 1000));
doors[2].setSize(Vector2f(100, 100));
doors[2].setPosition(Vector2f(650, 700));
}
for (auto& door: doors){
FloatRect playerBounds = player.getGlobalBounds();
FloatRect doorBounds = door.getGlobalBounds();
for ( auto it = doors.begin(); it != doors.end();)
{
if(doorBounds. intersects(playerBounds)) {
it = doors.erase(it);
}
else
{
++it;
}
window.draw(doors[1]);
window.draw(doors[2]);
}
}
for (auto& door: doors)
{
FloatRect playerBounds = player.getGlobalBounds();
FloatRect doorBounds = door.getGlobalBounds();
for ( auto it = doors.begin(); it != doors.end();)
{
if(doorBounds.intersects(playerBounds)) {
You are looping through every door (outer for loop), and for each of those doors you are looping through every door again (inner for loop). If the current door from the outer loop intersects the players bounds then you are deleting every door in the inner loop. You likely don't need these nested for loops.
One thing that might be helpful is to look up how to use a debugger. A debugger would allow you to step through one line of code at a time while your program is running to get a better understanding of what's happening. You can usually spot this type of problem pretty quickly with a debugger.
std::remove_if works perfectly for removing all instances which intersect. Here's a CME:
template <typename T>
std::ostream& operator << (std::ostream& out, sf::Rectangle<T> r)
{
out << "[ " << r.left << ", " << r.bottom << ", " << r.width << ", " << r.height << " ]";
return out;
}
int main()
{
sf::FloatRect playerBounds = { 0.f, 0.f, 10.f, 10.f };
std::vector<sf::FloatRect> doors =
{
sf::FloatRect(-2.f, 0.f, 10.f, 10.f),
sf::FloatRect(-20.f, 0.f, 10.f, 10.f),
sf::FloatRect(2.f, 0.f, 10.f, 10.f),
sf::FloatRect(0.f, 20.f, 10.f, 10.f),
};
std::cout << "Doors before: " << std::endl;
for (auto door : doors)
{
std::cout << door << std::endl;
}
doors.erase(std::remove_if(doors.begin(), doors.end(),
[playerBounds](const sf::FloatRect& door)
{
return playerBounds.intersects(door);
}), doors.end());
std::cout << "Doors after: " << std::endl;
for (auto door : doors)
{
std::cout << door << std::endl;
}
return 0;
}
And the output:
Doors before:
[ -2, 0, 10, 10 ]
[ -20, 0, 10, 10 ]
[ 2, 0, 10, 10 ]
[ 0, 20, 10, 10 ]
Doors after:
[ -20, 0, 10, 10 ]
[ 0, 20, 10, 10 ]