其他分享
首页 > 其他分享> > c – 如何通过引用正确传递迭代器?

c – 如何通过引用正确传递迭代器?

作者:互联网

我有一个游戏,我检查子弹和敌人之间的碰撞,我存储为2个矢量容器.人们说如果你要删除for循环中的元素,你最好使用迭代器,所以我做了.但我现在有一个问题,即将迭代器传递给函数.问题是我不一定需要擦除元素,所以它必须更复杂一些.

这是我检查碰撞的方式. “CircularCollision”工作正常,没有错误.

void ResolveColision(Weapon &weap, Map &map)
{
    std::vector<Bullet> bullets = weap.GetBullets();

    if (!bullets.empty())
    {
        for (std::vector<Bullet>::iterator i = bullets.begin(); i != bullets.end(); ++i)
        {
            std::vector<Enemy> enemies = map.GetEnemies();

            if (!enemies.empty())
            {
                for (std::vector<Enemy>::iterator j = enemies.begin(); j != enemies.end(); ++j)
                {
                    if (CircularCollision((*i), (*j)))
                    {
                        weap.DeleteByIndex(i);
                        map.TakeDamageByIndex(j, weap.GetDamage());
                        std::cout << "HIT!\n";
                    }
                }
            }
        }
    }
}

这是减少敌人健康的方法:

void Map::TakeDamageByIndex(std::vector<Enemy>::iterator &itr, int damage)
{
   (*itr).SetHealth((*itr).GetHealth() - damage);
}

这是删除子弹的方法:

void Weapon::DeleteByIndex(std::vector<Bullet>::iterator &itr)
{
    destroySprite((*itr).GetSprite());
    bullets.erase(itr);
}

我确定它看起来很可怕而且应该不起作用,但我不知道如何正确地做到这一点.请帮忙!
此外,当for循环使用索引(例如bullets [i])操作时,两种方法都能正常工作,在这种情况下,问题是“向量下标超出范围”错误.

解决方法:

在DeleteByIndex()中,更改此:

bullets.erase(itr);

对此:

itr = bullets.erase(itr);

std :: vector :: erase()将一个迭代器返回到被删除元素之后的下一个剩余元素.下一个元素是外循环在下一次迭代时需要继续的位置.

因此,您需要将外部循环从for更改为while,否则您将跳过元素(事实上,当您仍在使用索引时,原始代码会遇到该问题):

void ResolveColision(Weapon &weap, Map &map)
{
    std::vector<Bullet> bullets = weap.GetBullets();

    std::vector<Bullet>::iterator bullerItr = bullets.begin();
    while (bullerItr != bullets.end())
    {
        std::vector<Enemy> enemies = map.GetEnemies();
        bool wasAnyHit = false;

        for (std::vector<Enemy>::iterator enemyItr = enemies.begin(); enemyItr != enemies.end(); ++enemyItr)
        {
            if (CircularCollision(*bulletItr, *enemyItr))
            {
                wasAnyHit = true;
                weap.DeleteByIndex(bulletItr);
                map.TakeDamageByIndex(enemyItr, weap.GetDamage());
                std::cout << "HIT!\n";
                break;
            }
        }

        if (!wasAnyHit)
            ++bulletItr;
    }
}

话虽这么说,我建议用std :: find_if()代替内部循环.并重命名DeleteByIndex()和TakeDamageByIndex(),因为它们不再采用索引.事实上,我不会将迭代器传递给TakeDamage …(),而是传递实际的Enemy对象.或者更好的是,将TakeDamage()移入Enemy本身.

尝试更像这样的东西:

void ResolveColision(Weapon &weap, Map &map)
{
    auto bullets = weap.GetBullets();

    auto bulletItr = bullets.begin();
    while (bulletItr != bullets.end())
    {
        auto enemies = map.GetEnemies();
        auto &bullet = *bulletItr;

        auto enemyHit = std::find_if(enemies.begin(), enemies.end(),
          [&](Enemy &enemy){ return CircularCollision(bullet, enemy); }
        );

        if (enemyHit != enemies.end())
        {
            weap.DeleteBulletByIterator(bulletItr);
            enemyHit->TakeDamage(weap.GetDamage());
            std::cout << "HIT!\n";
        }
        else
            ++bulletItr;
    }
}

void Enemy::TakeDamage(int damage)
{
   SetHealth(GetHealth() - damage);
}

void Weapon::DeleteBulletByIterator(std::vector<Bullet>::iterator &itr)
{
    destroySprite(itr->GetSprite());
    itr = bullets.erase(itr);
}

标签:c,vector,visual-c,iterator,stdvector
来源: https://codeday.me/bug/20190827/1745659.html