表达式:向量下标超出范围
Expression: vector subscript out of range
我正在通过 SFML 制作一个简单的游戏,遇到了以下错误:
调试断言失败!
表达式:向量下标超出范围
此错误仅在 'rocket' 与第一个 'enemy' 接触时出现,同时屏幕上同时有 3 个敌人。我知道这与我在 for 循环中从向量中删除元素这一事实有关,但我能否得到一个明确的答案,说明为什么只有当屏幕上有 3 个或更多敌人时才会出现此错误。另外,我怎样才能重写我的代码,以便我可以从 enemy 向量中删除 'enemy' 元素而不导致错误?提前致谢
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();
}
}
}
Also, how could I rewrite my code so that I can remove the 'enemy'
elements from the enemies vector without causing an error?
如果允许更改 Rocket
和 Enemy
,最简单的更改是添加一个 bool
成员来表示对象是活的还是死的。然后,只需将对象标记为已死,而无需实际从容器中删除该对象。然后在循环之后,移除死对象。
Enemy
和 Rocket
类 所需的更改是添加一个 bool
成员,表示是否需要删除对象:
class Enemy
{
bool destroyed;
//...
public:
Enemy() : destroyed(false) {}
bool is_destroyed() const { return destroyed; }
void set_destroyed() { destroyed = true; }
};
class Rocket
{
bool destroyed;
//...
public:
Rocket() : destroyed(false) {}
bool is_destroyed() const { return destroyed; }
void set_destroyed() { destroyed = true; }
};
更改完成后,主循环的可能代码更改如下:
#include <algorithm>
//...
for (int i = 0; i < rockets.size(); i++)
{
if ( rockets[i]->is_destroyed() ) // skip if this was destroyed
continue;
for (int j = 0; j < enemies.size(); j++)
{
if (enemies[j]->is_destroyed()) // skip if this was destroyed
continue;
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);
// "destroy" these items
rocket->set_destroyed();
enemy->set_destroyed();
if (score % 5 == 0) levelUp();
printf("rocket intersects with enemy \n");
break; // since the rocket is destroyed,
}
}
}
// remove the dead items
// first partition the dead items off from the live items
auto iter = std::stable_partition(rockets.begin(), rockets.end(), [](rocket *r)
{return r->is_destroyed();});
// issue a delete call on these items.
std::for_each(rockets.begin(), iter, [](rocket *r) { delete r; });
// now erase from the container
rockets.erase(rockets.begin(), iter);
// do similar for the enemies container
auto iter2 = std::stable_partition(enemies.begin(), enemies.end(), [](enemy *e)
{return e->is_destroyed();});
std::for_each(enemies.begin(), iter2, [](enemy *e) { delete e; });
enemies.erase(enemies.begin(), iter2);
基本上我们标记要销毁的物品,然后循环完成后再处理。我们处理它们的方法是使用std::stable_partition
对死项进行分区,对分区左侧的每个项调用delete
,最后将它们从容器中删除。
我没有简单地使用 std::remove_if
的原因是 remove_if
算法使要删除的项目无效,因此尝试发出 delete
调用将导致未定义的行为。因此,首先将 "dead" 项目分区,然后 delete
-ing 它们,然后最后擦除它们 IMO 更安全。
我正在通过 SFML 制作一个简单的游戏,遇到了以下错误:
调试断言失败! 表达式:向量下标超出范围
此错误仅在 'rocket' 与第一个 'enemy' 接触时出现,同时屏幕上同时有 3 个敌人。我知道这与我在 for 循环中从向量中删除元素这一事实有关,但我能否得到一个明确的答案,说明为什么只有当屏幕上有 3 个或更多敌人时才会出现此错误。另外,我怎样才能重写我的代码,以便我可以从 enemy 向量中删除 'enemy' 元素而不导致错误?提前致谢
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();
}
}
}
Also, how could I rewrite my code so that I can remove the 'enemy' elements from the enemies vector without causing an error?
如果允许更改 Rocket
和 Enemy
,最简单的更改是添加一个 bool
成员来表示对象是活的还是死的。然后,只需将对象标记为已死,而无需实际从容器中删除该对象。然后在循环之后,移除死对象。
Enemy
和 Rocket
类 所需的更改是添加一个 bool
成员,表示是否需要删除对象:
class Enemy
{
bool destroyed;
//...
public:
Enemy() : destroyed(false) {}
bool is_destroyed() const { return destroyed; }
void set_destroyed() { destroyed = true; }
};
class Rocket
{
bool destroyed;
//...
public:
Rocket() : destroyed(false) {}
bool is_destroyed() const { return destroyed; }
void set_destroyed() { destroyed = true; }
};
更改完成后,主循环的可能代码更改如下:
#include <algorithm>
//...
for (int i = 0; i < rockets.size(); i++)
{
if ( rockets[i]->is_destroyed() ) // skip if this was destroyed
continue;
for (int j = 0; j < enemies.size(); j++)
{
if (enemies[j]->is_destroyed()) // skip if this was destroyed
continue;
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);
// "destroy" these items
rocket->set_destroyed();
enemy->set_destroyed();
if (score % 5 == 0) levelUp();
printf("rocket intersects with enemy \n");
break; // since the rocket is destroyed,
}
}
}
// remove the dead items
// first partition the dead items off from the live items
auto iter = std::stable_partition(rockets.begin(), rockets.end(), [](rocket *r)
{return r->is_destroyed();});
// issue a delete call on these items.
std::for_each(rockets.begin(), iter, [](rocket *r) { delete r; });
// now erase from the container
rockets.erase(rockets.begin(), iter);
// do similar for the enemies container
auto iter2 = std::stable_partition(enemies.begin(), enemies.end(), [](enemy *e)
{return e->is_destroyed();});
std::for_each(enemies.begin(), iter2, [](enemy *e) { delete e; });
enemies.erase(enemies.begin(), iter2);
基本上我们标记要销毁的物品,然后循环完成后再处理。我们处理它们的方法是使用std::stable_partition
对死项进行分区,对分区左侧的每个项调用delete
,最后将它们从容器中删除。
我没有简单地使用 std::remove_if
的原因是 remove_if
算法使要删除的项目无效,因此尝试发出 delete
调用将导致未定义的行为。因此,首先将 "dead" 项目分区,然后 delete
-ing 它们,然后最后擦除它们 IMO 更安全。