Я пытаюсь сделать первую игру симуляром Танкам. Но моя игра падает, когда я пытаюсь удалить вражеский танк (иногда работает, иногда нет), и я не знаю, что не так с моим кодом. Ты мне поможешь?
void Game::update(sf::Time elapsedTime){
if (enemies.size() < 6){
eTank1 = new EnemyTank(150, 130);
enemies.push_back(eTank1);
}
tank->move(elapsedTime);
for (vector<EnemyTank*>::const_iterator it = enemies.begin(); it != enemies.end();)
{
if (collision->checkCollisionWithEnemyTankAndTank(tank, *it)){
(*it)->move(elapsedTime);
}
collision->checkShoot(tank->getBulletsVector(), tank, *it);
//probably there is a problem
if ((*it)->getlife() <= 0){
delete *it;
enemies.erase(it);
cout << "TANGO DOWN" << endl;
}
++it;
}
checkShoot выглядит так:
void Collision::checkShoot(vector <Bullet*> &bullet, Tank *tank, EnemyTank* enemyTank){
distance = 0;
for (int i = 0; i < bullet.size(); i++){
distance = abs(bullet[i]->getPosition().x - enemyTank->getPosition().x) + abs(bullet[i]->getPosition().y - enemyTank->getPosition().y);
if (distance < 45){
cout << "act life: " << enemyTank->getlife() << endl;
enemyTank->setLife(); // -0.5 from actual life
tank->setVector(i); // delete bullet from vector
}
}
}
И код деструктора
cout << "DESTRU";
delete tank_bullet;
for (auto &it : bullets){ delete it; } bullets.clear();
cout << "DESTRU T - END\n";
Наконец, setVector (i);
void setVector(int index){
if (!bullets.empty()){
delete (bullets.at(index));
bullets.erase(bullets.begin() + index);
}
}
Ответ действительно в комментариях, но в случае, если они кажутся слишком краткими, я пишу немного более длинное объяснение.
Вот минимальный пример, похожий по стилю на ваш код:
int main() {
auto v = std::vector<int> {1, 2, 3, 4, 5};
for(auto it = v.cbegin(); it != v.cend(); ) {
if(*it == 5)
v.erase(it);
++it;
}
}
Это segfaults (нет, если вы сравниваете с чем-то, что не является последним элементом vector
, например *it == 3
, но это поведение, вероятно, зависит от компилятора). Зачем? v.erase(it)
аннулирует Итератор it
, так что вы не можете использовать it
после этой строки. Вместо этого, вы должны использовать то, что erase
возвращается, it = v.erase(it)
, который является итератор после удаленной. Теперь, если это будет v.cend()
а на следующей строке вы увеличиваете его, ++it
, вы находитесь вне пределов и не повезло.
Я не поощряю вас использовать следующее, но если вы хотите придерживаться стиля своего кода, то что должно работать
if(*it == 5)
it = v.erase(it);
else
++it;
Что else
делает, так это то, что он избегает двойного приращения при erase
.
erase
приведет к аннулированию итераторов. Однако вас может заинтересовать то, что возвращает функцияerase
.