Итерация по двум векторам и удаление указанных c позиций - PullRequest
0 голосов
/ 17 февраля 2020

Я создаю игру и пытаюсь определить обнаружение столкновений. Я получил четыре класса на данный момент. Игра, Игрок, Снаряд и Враг. Поэтому, если я стреляю с помощью игрока или врага, я создаю новый снаряд и emlace_back() превращаю его в вектор. Все мои враги также хранятся внутри вектора. Все тезисы Объекты созданы с новыми. Таким образом, мои обнаружения столкновений выглядят так:

void Game::CheckHit() {

    auto enemy = m_Enemys.begin();
    auto projectile = m_Projectiles.begin();


    while(projectile != m_Projectiles.end()){

        if (//Hit Detected with player) {
            delete (*projectile);
            m_Projectiles.erase(projectile);
            m_Player->PlayerHit();
        }

        while (enemy != m_Enemys.end()) {
            if (//Hit Detected with enemy) {

                delete (*enemy);
                delete (*projectile);
                m_Projectiles.erase(projectile);
                m_Enemys.erase(enemy);
                m_Player->BulletHit();
            } else 
                enemy++;    
        }
    }
}

Проблема, с которой я столкнулся, заключается в том, что я на самом деле не знаю, когда мне следует увеличивать итератор снаряда, потому что мне нужно делать это только в том случае, если ни игрок, ни Enemys не получили его с помощью что специфицирует c снаряд. Любая помощь приветствуется.

Ответы [ 2 ]

1 голос
/ 17 февраля 2020

Если снаряд попадет в игрока, которого вы удалите, то продолжать использовать его будет UB. Вместо этого вам нужно начать проверку следующего снаряда.

Также обратите внимание, что erase возвращает итератор для элемента после стертого, поэтому при удалении не следует увеличивать итератор, просто используйте то, что возвращается из erase.

Я также рекомендую вам использовать вектор умных указателей вместо сырых указателей. Затем вы можете просто вызвать erase и не нужно вручную delete каждый объект.

Это может выглядеть так:

void Game::CheckHit() {
    for(auto projectile = m_Projectiles.begin(); projectile != m_Projectiles.end();) {
        bool hit = false;

        if(/*Hit player*/) {
            hit = true;
            m_Player->PlayerHit();
        } else {
            for(auto enemy = m_Enemys.begin(); enemy != m_Enemys.end();) {
                if(/* Hit enemy*/) {
                    hit = true;
                    enemy = m_Enemys.erase(enemy);
                    m_Player->BulletHit();
                    break;
                } else {
                    ++enemy;
                }
            }
        }

        if(hit) projectile = m_Projectiles.erase(projectile);
        else ++projectile;
    }
}    
0 голосов
/ 17 февраля 2020

Если вы делаете такое случайное удаление, это, конечно, не выглядит, что std::vector - подходящий контейнер для вас. Я бы предложил std::list или std::forward_list. Вы обнаружите, что std::list::erase() возвращает итератор для следующего элемента, так что вы можете продолжить свой l oop с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...