Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to erase an vector element in this situation?

I made a game, rambo shoots bullets and bullets hit zombies and I want to erase the zombie who got hit, from the zombie vector.

This nested loop checks collision between every zombie and bullet one by one. It works good for a while but when I start killing more, at some point, it crashes because it wants to use a function of erased zombie.

for ( it = zombies.begin(); it != zombies.end(); ++it ) {
    it->attack();
    for (rambo.it = rambo.bullets.begin(); rambo.it != rambo.bullets.end(); ++rambo.it) {
        if(checkBasicCollision(it,rambo.it) && it != zombies.end()){
            zombies.erase(it);
        }
    }
}

I've added it--; after zombies.erase(it); works better now but it still crashes sometimes.

I think its happening like, for example there are 5 zombies and 20 bullets, zombie iterator is at second zombie, and second zombie starts the bullet loop to check if it got hit. Loop starts, lets say third bullet hit the zombie, but loop is still going, even if zombie is erased, it still continues the loop.

I've added break; after zombies.erase(it); now it hasn't got any problem. But the code looks so dirty. Is there another way to erase the current element easily

like image 498
user3858240 Avatar asked Feb 02 '26 05:02

user3858240


1 Answers

While the solution for manually erasing was presented, note that it is not the most idiomatic one. In idiomatic C++ you would make use of the std::remove_if algorithm in the erase-remove idiom like so:

// 1. A predicate that check whether a zombie was it by any bullet:
auto is_zombie_hit = [&rambo](Zombie const& zombie) {
    auto is_bullet_hitting_zombie = [&zombie](Bullet const& bullet) {
        return checkBasicCollision(zombie, bullet);
    };

    return std::any_of(
        rambo.bullets.begin(),
        rambo.bullets.end(),
        is_bullet_hitting_zombie
    );
};

// 2. Use the erase-remove idiom:
zombies.erase(
    std::remove_if(zombies.begin(), zombies.end(), is_zombie_hit),
    zombies.end()
);

Note: yes, you can use lambda in-place, however I prefer naming them to indicate their role.

Note: this uses C++11, however replacing lambda with predicates is trivial and an implementation of any_of is easy enough to produce, much like all_of and none_of.

like image 176
Matthieu M. Avatar answered Feb 04 '26 17:02

Matthieu M.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!