【发布时间】:2019-08-10 01:42:24
【问题描述】:
我正在通过SFML制作一个简单的游戏,遇到以下错误:
调试断言失败! 表达式:向量下标超出范围
此错误仅在“火箭”与第一个“敌人”接触而屏幕上同时有 3 个敌人时出现。我知道这与我在 for 循环中从向量中删除元素这一事实有关,但我能否明确回答为什么此错误仅在屏幕上有 3 个或更多敌人时发生。另外,我怎样才能重写我的代码,以便我可以从敌人向量中删除“敌人”元素而不会导致错误?提前致谢
for (int i = 0; i < rockets.size(); i++) //This is where the error points to
{
for (int j = 0; j < enemies.size(); j++)
{
Rocket *rocket = rockets[i];
Enemy *enemy = enemies[j];
if (checkCollision(rocket->getSprite(), enemy->getSprite()))
{
//hitSound.play();
score++;
std::string finalScore = "Score: " + std::to_string(score);
scoreText.setString(finalScore);
sf::FloatRect scoreBounds = scoreText.getGlobalBounds();
scoreText.setOrigin(scoreBounds.width / 2, scoreBounds.height / 2);
scoreText.setPosition(viewSize.x * 0.5f, viewSize.y * 0.10f);
rockets.erase(rockets.begin() + i);
enemies.erase(enemies.begin() + j);
delete(rocket);
delete(enemy);
if (score % 5 == 0) levelUp();
printf("rocket intersects with enemy \n");
}
}
}
我已将敌人和火箭对象存储在向量中:
std::vector <Enemy*> enemies;
std::vector <Rocket*> rockets;
如果有帮助,这是我的整个更新功能:
void update(float dt)
{
hero.update(dt);
currentTime += dt;
if (currentTime >= prevTime + 1.125f)
{
spawnEnemy();
prevTime = currentTime;
}
for (int i = 0; i < enemies.size(); i++)
{
Enemy *enemy = enemies[i];
enemy->update(dt);
if (enemy->getSprite().getPosition().x < 0)
{
enemies.erase(enemies.begin() + i);
delete(enemy);
gameOver = true;
gameOverSound.play();
}
}
for (int i = 0; i < rockets.size(); i++)
{
Rocket *rocket = rockets[i];
rocket->update(dt);
if (rocket->getSprite().getPosition().x > viewSize.x)
{
rockets.erase(rockets.begin() + i);
delete(rocket);
}
}
for (int i = 0; i < rockets.size(); i++)
{
for (int j = 0; j < enemies.size(); j++)
{
Rocket *rocket = rockets[i];
Enemy *enemy = enemies[j];
if (checkCollision(rocket->getSprite(), enemy->getSprite()))
{
//hitSound.play();
score++;
std::string finalScore = "Score: " + std::to_string(score);
scoreText.setString(finalScore);
sf::FloatRect scoreBounds = scoreText.getGlobalBounds();
scoreText.setOrigin(scoreBounds.width / 2, scoreBounds.height / 2);
scoreText.setPosition(viewSize.x * 0.5f, viewSize.y * 0.10f);
rockets.erase(rockets.begin() + i);
enemies.erase(enemies.begin() + j);
delete(rocket);
delete(enemy);
if (score % 5 == 0) levelUp();
printf("rocket intersects with enemy \n");
}
}
}
for (int i = 0; i < enemies.size(); i++)
{
Enemy *enemy = enemies[i];
if (checkCollision(enemy->getSprite(), hero.getSprite()))
{
gameOver = true;
gameOverSound.play();
}
}
}
【问题讨论】:
-
如果
i是rockets.size() - 1并且j尚未到达enemies.size()-1,请考虑内循环会发生什么。如果内循环删除了rockets[i]和enemies[j],内循环体将再次执行并访问rockets不存在的元素。这会导致未定义的行为。if然后取消引用rockets[i](更多未定义的行为)并且,如果测试为真,则删除它 - 这几乎肯定会破坏程序使用的内存。 -
一般来说,尽量避免擦除正在迭代的容器中的元素。您有
erase/remove习惯用法,它允许擦除符合特定条件的项目,而无需编写擦除循环。 -
另外,您可以将对象标记为“已死”,而不是实际删除它们。然后在循环之后,只需使用
erase/remove_if删除死对象。这需要为每个类添加一个bool成员。 -
另外,为了回答您的问题,我们想看看
Rocket和Enemy的定义是什么。
标签: c++ visual-studio sfml