我试图迭代存储的std::unique_ptr<Enemy>
的向量,以检查它们是否与player
的攻击发生冲突。如果是,我想从向量中删除Enemy
。
但是,当我这样做时,我收到错误:
文件:c:\ program files(x86)\ microsoft visual studio 14.0 \ vc \ include \ vector 行:102 表达式:向量迭代器不可递增
以下是代码:
if(actionCnt > 0)
{
sf::FloatRect* playerAction = player->action(actionCnt);
if (!enemies.empty()) {
for (auto&i : enemies) {
if (playerAction->intersects(i->getBox())) {
i->kill();
enemies.erase(std::remove(enemies.begin(), enemies.end(), i));
}
}
}
delete playerAction;
playerAction = NULL;
}
基本上,如果玩家触发攻击,actionCnt
会转到1并且此段会被执行。
playerAction
是一个可以移动以模拟挥杆的矩形,所以我在这里检查矩形是否与敌人发生碰撞,如果是这样的话会杀死它。
我使用的是SFML库,但应该明白这些类的功能。
现在我只有1名敌人在场上测试这些东西。所以当我点击它时,enemies
向量应为空。
答案 0 :(得分:3)
代码中的auto
将返回向量容器中的类型。它不会给你迭代器。您可以使用经典for循环并使用迭代器擦除元素,而不是基于范围的for循环。
if (!enemies.empty())
{
for (auto itr = std::begin(enemies); itr!=std::end(enemies); ++itr)
{
if ((*itr)->hit)
{
(*itr)->kill();
enemies.erase(itr);
}
}
}
或者你可以在std :: remove_if中使用lambda函数并在一行中完成整个操作。这实际上被称为擦除 - 删除习语(更多here)。简而言之,remove_if以保留顺序的方式移动(移动)容器中从lambda函数返回false的所有元素,并将迭代器返回到最后一个元素之后的迭代器。从lambda函数返回true的元素将移动到向量的末尾,但仍然是不可引用的,但尚未定义。要完全擦除元素,将调用向量的擦除函数以从逻辑端(迭代器从std :: remove_if)到容器的物理端(vector.end())删除所有元素。
if (!enemies.empty())
enemies.erase(std::remove_if(enemies.begin(),enemies.end(),[](const auto &itr){return itr->hit;}),std::end(enemies));
此外,当您想要对元素执行操作而不改变容器本身时,使用基于范围的for循环。对于更安全的代码,您可以使用while循环而不是基于范围的for循环。
if (!enemies.empty())
{
auto itr = std::begin(enemies);
while (itr != std::end(enemies) )
{
if ((*itr)->hit)
{
(*itr)->kill();
enemies.erase(itr);
}
++itr;
}
}
您可以在此处查看代码:http://rextester.com/EHLB11709 我试图模仿你的游戏逻辑只关注删除部分。从输出中,您将看到第6个元素已被删除。
此外,如果您要删除矢量中的所有内容,则应使用clear()
。