我正在迭代向量std::vector<Bullet*> bullets
,我正在寻找与敌人的碰撞。它在每种情况下都很有效,除了以下情况:最后发射的子弹(必须有多个)与敌人发生碰撞。
代码 -
for(std::vector<Bullet*>::iterator it = bullets.begin(); it != bullets.end(); ++it)
{
if ((*it)->getSprite()->getGlobalBounds().intersects(enemy->getSprite()->getGlobalBounds()))
{
delete *it;
bullets.erase(it);
enemy->destroy();
if (bullets.size() == 0)
break;
}
}
我评论了for
循环中的特定元素,发现bullet.erase(it)
调用崩溃了程序。
发生崩溃时,我收到一个返回码:134(0x86)。这段代码有什么问题?
(*it)->getSprite()
返回指向Bullet
类精灵的指针。
答案 0 :(得分:1)
如何使用remove_if
和erase
组合:
auto is_hit = [&enemy](Bullet *bullet)
{
if (bullet->getSprite()->getGlobalBounds().intersects(enemy->getSprite()->getGlobalBounds()))
{
delete bullet;
enemy->destroy();
return true;
}
return false;
};
bullets.erase(std::remove_if(bullets.begin(), bullets.end(), is_hit), bullets.end());
答案 1 :(得分:1)
供您考虑:
以下代码片段展示了我如何从尾部清理向量(使用push_back()将元素添加到尾部的补充操作)
while(!gBoard.empty())
{
Cell_t* cell = gBoard.back(); // fetch last element (a ptr)
gBoard.pop_back(); // remove last element
delete cell; // remove cell from heap - raw pointer
}
也许你可以做这种清洁风格并使用多个载体......它仍然可能比其他选择更快。
在你的问题中,每个子弹似乎至少有两个目的地......命中或错过。
while ( ! Bullets.empty() ) // spin through bullet list
{
Bullet* aBullet = Bullets.back(); // fetch copy of last element
Bullets.pop_back(); // remove last element
if (*aBullet)-> getSprite()->getGlobalBounds().
intersects(enemy->getSprite()->getGlobalBounds()))
{
// HIT!
Hit.push_back(aBullet); // capture the element to Hit bucket
enemy->destroy(); // tbd - a decision? or always final?
// no delete
if (bullets.size() == 0) // no more to compute, redundant to while
break;
}
else
{
// MISS
Missed.push_back(aBullet); // capture element to Missed bucket
}
} // while
assert(bullets.empty()); // bullets have been consumed
// clean up spent bullets that intersected
while (! Hit.empty() )
{
Bullet* aBullet = Hit.back(); // copy last element from Hit
Hit.pop_back(); // remove last element from Hit
delete aBullet; // tbr - delete the dynamic memory
}
// clean up spent bullets that missed
// move the bullet from Missed vec back into Bullets vec
// for tbd - furthur evaluation ... did the bullet hit any other obj
// the following also happens to 'undo' the seq reversal
while (! Missed.empty() )
{
Bullets.push_back (Missed.back()); // copy last element from Missed
Missed.pop_back(); // remove last element from Missed
// tbd - also delete the missed bullet?
// or do you check for these bullets to collide with other objects
}
// possibly a copy can do this last loop, but this is simple and
// undoes the reversal.
答案 2 :(得分:0)
并发现bullet.erase(it)调用[for the last element] 崩溃程序
从某种意义上说,你可能过早地进行了擦除。
请考虑以下事项:
范围,目标和武器类型的测试参数可能结合起来,例如达到10%的命中率。因此,在1000次射击的集合中,(1000 == bullets.size()),会有(〜)100颗子弹击中目标。
您的代码找到每个元素,并使用bullets.erase()在向量中创建100个“洞”。因为矢量数据是连续的,所以擦除方法还移动其他元素以填充由擦除创建的孔。 (具体实现方式可能有所不同。)
一般来说,每次100次擦除会导致100次洗牌少于(最多)1000个元素......这种一次一个接近的方法可能是一个相对“缓慢”的过程。
作为当前设计的替代方案,而不是查找和擦除,推迟擦除,直到您的代码识别并标记所有“相交”。
你可以用相同的方式找到相交(点击),但是“标记”它们,不要删除它们。选项包括向Bullet类添加bool,或者维护匹配的bool向量以保存每个项目符号。
使用两个索引
- i1初始化为0(第一个(最左侧)向量元素)和
- i2初始化为(bullets.size() - 1)[最后(最右边)向量元素]
- 旋转增量i1以找到第一个命中,
- 旋转递减i2以找到最后一个未命中,
- 然后是std :: swap(项目符号[i1],项目符号[i2])
重复直到i1&gt; = i2
现在所有命中都是连续的并且在向量的尾部,执行100次命中的单次删除
这应该可以消除任何改变。
此外,不应使用擦除元素......因为擦除发生在流程结束时。