首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在这种情况下如何擦除向量元素?

在这种情况下如何擦除向量元素?
EN

Stack Overflow用户
提问于 2014-07-21 00:24:25
回答 5查看 378关注 0票数 2

我做了一个游戏,兰博发射子弹,子弹击中僵尸,我想从僵尸矢量中删除被击中的僵尸。

此嵌套循环逐个检查每个僵尸和子弹之间的碰撞。它工作了一段时间,但当我开始杀死更多的时候,它崩溃了,因为它想要使用一个删除僵尸的功能。

代码语言:javascript
复制
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);
        }
    }
}

我在zombies.erase(it);之后添加了it--;,现在它工作得更好了,但它有时仍然会崩溃。

我认为这就像是,例如,有5个僵尸和20颗子弹,僵尸迭代器在第二个僵尸,第二个僵尸开始子弹循环来检查它是否被击中。循环开始,假设第三颗子弹击中僵尸,但循环仍在进行,即使僵尸被擦除,它仍然继续循环。

我添加了break;在zombies.erase(it);之后,它现在没有任何问题。但是代码看起来太脏了。是否有其他方法可以轻松地擦除当前元素

EN

回答 5

Stack Overflow用户

发布于 2014-07-21 00:49:04

虽然提出了手动擦除的解决方案,但请注意,这并不是最常用的解决方案。在惯用的C++中,您可以使用擦除-删除习惯用法中的std::remove_if算法,如下所示:

代码语言:javascript
复制
// 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()
);

注意:可以,您可以就地使用lambda,但我更喜欢为它们命名以表示它们的角色。

注意:这使用了C++11,但是用谓词替换lambda很简单,而且any_of的实现很容易生成,就像all_ofnone_of__一样。

票数 5
EN

Stack Overflow用户

发布于 2014-07-21 00:26:53

要使用erase,您需要使用返回值并将其分配回迭代器,以便它在下一次迭代中有效。

代码语言:javascript
复制
for ( it = zombies.begin(); it != zombies.end(); ) {
    it->attack();
    for (rambo.it = rambo.bullets.begin(); rambo.it != rambo.bullets.end(); ++rambo.it) {
        if(checkBasicCollision(it,rambo.it) && it != zombies.end()){
            it = zombies.erase(it);    // erase will increment the iterator
        }
        else{
            ++it;    // no erase, increment the iterator manually
        }
    }
}

vector::erase的文档中,返回值是:

一个迭代器,指向被函数调用擦除的最后一个元素后面的元素的新位置。如果操作擦除了序列中的最后一个元素,则这是容器结束。

票数 4
EN

Stack Overflow用户

发布于 2014-07-21 00:44:00

可能是这样的:

代码语言:javascript
复制
auto zombie_tail = std::remove_if(zombies.begin(), zombies.end(), [&](Zombie const & zombie) {
        zombie.attack();
        return std::any_of(rambo.bullets.begin(), rambo.bullets.end(), [&](Bullet const & bullet) {
            return checkBasicCollision(zombie, bullet);
        });
    });

zombies.erase(zombie_tail, zombies.end());

或者,如果您不想使用c++算法:

代码语言:javascript
复制
for (it = zombies.begin(); it != zombies.end(); ) {
    it->attack();

    // Attempt to find a bullet that hit.
    for(rambo.it = rambo.bullets.begin(); rambo.it != rambo.bullets.end(); ++rambo.it)
        if (checkBasicCollision(it, rambo.it))
            break;

    // Possibly remove the zombie, and advance the iterator
    if (rambo.it != rambo.bullets.end())
        it = zombies.erase(it);
    else
        ++it;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24852495

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档