我正在尝试迭代存储的std::unique_ptr<Enemy>
's向量,以检查它们是否与player
的攻击相碰撞。如果它们是,我想从向量中删除Enemy
。然而,当我这样做时,我得到了错误:
File: c:program files (x86)microsoft visual studio 14.0vcincludevector线:102表达式:vector迭代器不可递增
代码如下:
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库,但是这些类的功能应该是显而易见的。
现在我只有一个敌人在战场上测试这个东西。所以当我点击它的时候,enemies
向量应该是空的
代码中的auto
将返回vector容器内部的类型。它不会给你迭代器。可以使用经典的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函数,并在一行中完成整个操作。这实际上被称为擦除-删除习惯用法(更多信息在这里)。简而言之,remove_if以保留顺序的方式从lambda函数中移动(移动)容器中返回false的所有元素,并返回一个迭代器到最后一个元素的后面。从lambda函数返回true的元素被移动到vector的末尾,并且仍然是可解引用的,但未定义。要完全擦除元素,调用vector的erase函数删除容器逻辑端(从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()
.