我有一个游戏,我向目标射击子弹,然后删除被子弹击中的物体以及不在屏幕上的子弹。
例如:
std::vector<object> object_list;
for(size_t i = 0; i < object_list.size(); i++)
{
if(object_list[i].hit())
{
object_list.erase(object_list.begin() + i);
}
else
object_list[i].draw();
}
此问题是,当我删除对象时,向量的大小会减小,因此当检查条件时,向量会失败,并且会出现诸如“向量下标超出范围”之类的错误。我可以选择不渲染那些尚未被击中的小行星来渲染小行星,但是问题是没有。命中(分裂)时对象的数量增加,因此最终程序将变慢。对于屏幕外的项目符号,我使用了类似的概念,但是找不到解决方法。我正在寻找一种解决方案,以这种或更好的方式删除元素。
对象和项目符号都是类。
答案 0 :(得分:5)
您应该将循环分为两部分:
const { Parser } = require('json2csv');
const fields = ['field1', 'field2', 'field3'];
const opts = { fields };
try {
const parser = new Parser(opts);
const csv = parser.parse(myData);
console.log(csv);
} catch (err) {
console.error(err);
}
object_list.erase(std::remove_if(object_list.begin(),
object_list.end(), [](auto&& item) { return item.hit(); }),
object_list.end());
它更安全,更易读。
答案 1 :(得分:2)
与其他答案具有相同的想法,但是使用迭代器可以使此代码更容易
for (auto i = object_list.begin(); i != object_list.end(); )
{
if (i->hit())
{
i = object_list.erase(i);
}
else
{
i->draw();
++i;
}
}
vector::erase
将迭代器返回到下一个元素,您可以使用该元素继续循环。
答案 2 :(得分:2)
[...]我正在寻找这种或删除元素的更好方法的解决方案。
使用ranges::actions::remove_if
库中的range-v3操作,您可以使用功能性编程风格的方法来原位更改object_list
容器:
object_list |= ranges::actions::remove_if(
[](const auto& obj) { return obj.hit(); });
随后是随后的ranges:for_each
调用以绘制对象:
ranges::for_each(object_list, [](const auto& obj){ obj.draw(); });
DEMO。
答案 3 :(得分:1)
您可以执行以下操作:
for (size_t i = 0; i < object_list.size(); )
{
if (object_list[i].hit())
object_list.erase(object_list.begin() + i)
else
{
object_list[i].draw()
++i;
}
}
答案 4 :(得分:0)
让我们说您在i = 5处并且该对象已被命中,删除该元素后,i = 6处的obj移至i = 5,并且您尚未检查它,因此只需添加{{ 1}}。
另一种方法是-
i--;
此外,从矢量中删除对象可能会更快,在该矢量中执行将对象标记为命中的代码,这样,您只需要绘制列表中遗漏的所有对象即可。了解更多有关如何执行所有这些操作的背景将有助于确定更合适的特定方法:)
答案 5 :(得分:0)
显示的代码不会失败或给向量下标超出范围-它只是不考虑每个对象,因为它会在删除对象后跳过该元素。
有关采用C ++ 11及更高版本的概念的非常简短的解决方案,请参见answer by Equod或the one by dfri
为更好地理解问题,和/或如果您必须坚持使用索引进行for循环,则基本上有两种选择:
for (int i=object_list.size()-1; i>=0; --i)
{
if (object_list[i].hit())
{
object_list.erase(object_list.begin() + i)
}
else
{
object_list[i].draw()
}
}
i
not 删除了当前元素:for (int i=0; i<object_list.size(); /* No increase here... */ )
{
if (object_list[i].hit())
{
object_list.erase(object_list.begin() + i);
}
else
{
object_list[i].draw();
++i; // ...just here if we didn't remove the element
}
}
答案 6 :(得分:0)
我怀疑std::vector
不是您想要的容器(但是,我当然不知道整个代码)。每次擦除操作都意味着重新分配了向量的右部分(然后是对象的副本),这可能会非常昂贵。而您的实际问题是设计问题的症状。
从我看来,std::list
可能更好:
std::list<object> objects;
// ...
for(std::list<object>::iterator it = objects.begin(); it != objects.end();)
{
if(it->hit())
objects.erase(it++); // No object copied
else
{
it->draw();
++it;
}
}