2014-12-19 3 views
0

Я делаю игру на C++ и SFML. У меня странная ошибка, всякий раз, когда у меня ровно 1 враг и 3 выстрела на экране, и пуля сталкивается с противником, игра падает. Ошибки я получаю:SFML weird shoot bug

Expression: vector subscript out of range 

Это, как я проверить столкновения между выстрелами и врагов:

for (int i = 0; i < enemies.size(); i++) 
{ 
    for (int s = 0; s < shots.size(); s++) { 
     if (Collision::PixelPerfectTest(enemies[i].getSprite(), shots[s].getSprite())) { 
      enemies[i].setHealth(enemies[i].getHealth() - player.getDamage()); 
      if (enemies[i].getHealth() <= 0) { 
       enemies.erase(enemies.begin() + i); 
      } 
      shots.erase(shots.begin() + s); 
     } 
    } 
} 

«врагов» и «выстрелов» являются векторы, которые я вставляю в каждые х секунд в основной цикл. Вот код, который:

if (enemySpawner.getElapsedTime().asSeconds() >= 1.5f) { 
     enemies.push_back(Enemy(spriteManager.enemySprite)); 
     std::cout << enemies.size() << " enemies" << std::endl; 
     enemySpawner.restart(); 
    } 

    if (shotSpawner.getElapsedTime().asSeconds() >= 0.3f &&  sf::Mouse::isButtonPressed(sf::Mouse::Left)) { 
     shots.push_back(Shot(spriteManager.shotSprite, player.getPosition(), *window)); 
     std::cout << shots.size() << " shots" << std::endl; 
     shotSpawner.restart(); 
    } 

Как я уже говорил, это происходит только тогда, когда у меня есть 1 противника и 3 выстрела, в противном случае это, кажется, работает хорошо.

EDIT: теперь игра замерзает, когда появляется первый враг. Вот обновленный код:

//Shot vs enemy 
for (auto eit = enemies.begin(); eit != enemies.end();) 
{ 
    for (auto sit = shots.begin(); sit != shots.end();) { 
     if (Collision::PixelPerfectTest((*eit).getSprite(), (*sit).getSprite())) { 
      (*eit).setHealth((*eit).getHealth() - player.getDamage()); 
      if ((*eit).getHealth() <= 0) { 
       enemies.erase(eit); 
       shots.erase(sit); 
      } 
      shots.erase(sit); 
      eit = eit++; 
      sit = sit++; 
     } 
    } 
} 

ответ

0

@ Ответ moka объясняет основную проблему с вашим кодом, и его/ее код с использованием итераторов исправит вашу проблему. Однако есть еще один способ справиться с проблемой: разделение вашего кода на «прохождение вычислений» и «пропуск модификации массива». Код будет выглядеть следующим образом:

for (int i = 0; i < enemies.size(); i++) 
{ 
    for (int s = 0; s < shots.size(); s++) { 
     if (!enemies[i].alive || !shots[s].active) { 
      continue; 
     } 
     if (Collision::PixelPerfectTest(enemies[i].sprite(), shots[s].sprite())) { 
      shots[s].active = false; 
      enemies[i].setHealth(enemies[i].getHealth() - player.getDamage()); 
      if (enemies[i].getHealth() <= 0) { 
       enemies[i].alive = false; 
      } 
     } 
    } 
} 

enemies.erase(std::remove_if(enemies.begin(), enemies.end(), 
    [](Enemy const &e) { return !e.alive; }), enemies.end()); 

shots.erase(std::remove_if(shots.begin(), shots.end(), 
    [](Shot const &s) { return !s.active; }), shots.end()); 

Этот стиль также хорош, потому что он отделяет логику игры от реализации немного больше. Например, если вы хотите разрешить выстрел, чтобы нанести урон более чем одному врагу, вам все равно придется использовать такой подход для массива кадров.

Chapter on Double Buffering в отличной книге «Программирование шаблонов игр» углубляется.

0

вы не можете просто удалить материал из векторов в то время как итерации над ними так, как вы делаете, потому что это даст I значение, которые не будут находиться в диапазоне от вектора больше (после его размер уменьшился при вызове стирания), что в основном приведет к попытке индексировать значение массива, которое больше не существует. Если вам нужно такое поведение, это хорошая идея использовать итераторы:

auto eit = enemies.begin(); 
for (; eit != enemies.end();) 
{ 
    if((*eit).isDead()) 
    { 
     eit = enemies.erase(eit); 
    } 
    else 
    { 
     eit++; 
    } 
} 

вы могли бы сделать то же самое для массива выстрела.

+0

Спасибо, но теперь у меня другая проблема. Посмотреть мой отредактированный пост – Wahoozel