矢量下标超出范围

Vector subscript out of range

本文关键字:范围 下标      更新时间:2023-10-16

我的游戏有点问题。当我试图检查子弹和ennemy是否碰撞时,我随机得到一个错误"矢量下标超出范围",我不确定这是不是一个问题,但我在两个地方删除了我的矢量:

//Checking if enemy is crossing a bullet
        for (size_t i = 0; i < ennemies.size(); i++)
        {
            ennemies[i].update(player);
            if (player.getGlobalBounds().intersects(ennemies[i].getGlobalBounds()))
            {
                player.kill();
            }
            for (size_t j = 0; j < bullets.size(); j++)
            {
                if (ennemies[i].getGlobalBounds().intersects(bullets[j].getGlobalBounds()))
                {
                    ennemies.erase(ennemies.begin() + i);
                    bullets.erase(bullets.begin() + j);
                    ilosc--;
                }
            }
        }

这里是第二名:

for (int i = 0; i < Level::LEVEL_HEIGHT; i++)
{
    for (int j = 0; j < Level::LEVEL_WIDTH; j++)
    {
        if (level.tiles[i][j].tileType != 0)
        {
            if (x.intersects(map[i][j].getGlobalBounds()))
                kolX = true;
            else if (y.intersects(map[i][j].getGlobalBounds()))
                kolY = true;
            for (int k = 0; k < bullets.size(); k++)
            {
                if (bullets[k].getGlobalBounds().intersects(map[i][j].getGlobalBounds()))
                {
                    bullets.erase(bullets.begin() + k);
                    ilosc--;
                }
            }
        }
    }
}

这是一个主要类的全部代码:

    #include "Engine.h"
Engine::Engine()
{
    //wczytywanie bg
    bgTexture.loadFromFile("data\textures\bg.png");
    bgSprite.setTexture(bgTexture);
    //wczytywanie textur
    for (int i = 1; i < level.iloscTextur; i++)
    {
        tiles[i].loadFromFile("data\textures\tiles.png", IntRect((i-1)*level.TILE_WIDTH, 0, 32, 32));
    }
    //ustawianie kafli
    for (int i = 0; i < Level::LEVEL_HEIGHT; i++)
    {
        for (int j = 0; j < Level::LEVEL_WIDTH; j++)
        {
            if (level.tiles[i][j].tileType != 0)
            {
                map[i][j].setPosition(j * Level::TILE_WIDTH, i * Level::TILE_HEIGHT);
                map[i][j].setTexture(tiles[level.tiles[i][j].tileType]);
            }
        }
    }
}
Engine::~Engine()
{
}
//Renderowany poziom gry
void Engine::runEngine(RenderWindow & window)
{
    //Zegary do pętli stałokrokowej, pocisków i przeciwników
    Time UpdateTime = Time::Zero;
    Time czasOdPocisku = Time::Zero;
    Time czasDoSpawnu = Time::Zero;
    Clock przeciwnicy;
    Clock zegar;
    Clock czasPocisku;
    const Time StepTime = seconds(1.f / 60.f);
    const Time WaitTime = seconds(0.1);
    Time EnemySpawn = enemy.losujSpawn();
    bool menu = false;
    while (!menu)
    {
        Time czas = zegar.restart();
        UpdateTime += czas;
        //Pętla aktualizujaca logikę gry
        while (UpdateTime > StepTime)
        {
            czasOdPocisku = czasPocisku.getElapsedTime();
            czasDoSpawnu = przeciwnicy.getElapsedTime();
            UpdateTime -= StepTime;
            Event event;
            Vector2f mouse = window.mapPixelToCoords(Mouse::getPosition(window));   
            player.update(mouse);
            if (window.pollEvent(event))
            {
                if (event.type == Event::Closed)
                    menu = true;
                if ((Keyboard::isKeyPressed(Keyboard::Left) && WaitTime < czasOdPocisku) || (Keyboard::isKeyPressed(Keyboard::Right) && WaitTime < czasOdPocisku) ||
                    (Keyboard::isKeyPressed(Keyboard::Up) && WaitTime < czasOdPocisku) || (Keyboard::isKeyPressed(Keyboard::Down) && WaitTime < czasOdPocisku))
                {
                    czasPocisku.restart();
                    bullets.push_back(bullet);
                    bullets[ilosc].addBullet(player);
                    ilosc++;
                }
            }
            //Spawn przeciwników

            if (EnemySpawn < czasDoSpawnu)
            {
                czasDoSpawnu = przeciwnicy.restart();
                EnemySpawn = enemy.losujSpawn();
                for (int i = 0; i < enemy.losujPrzeciwnikow(); i++)
                    ennemies.push_back(enemy);
            }
            //aktualizacje logiki
            for (int i = 0; i < bullets.size(); i++)
            {
                bullets[i].update();
            }
            //Checking if enemy is crossing a bullet
            for (size_t i = 0; i < ennemies.size(); i++)
            {
                ennemies[i].update(player);
                if (player.getGlobalBounds().intersects(ennemies[i].getGlobalBounds()))
                {
                    player.kill();
                }
                for (size_t j = 0; j < bullets.size(); j++)
                {
                    if (ennemies[i].getGlobalBounds().intersects(bullets[j].getGlobalBounds()))
                    {
                        ennemies.erase(ennemies.begin() + i);
                        bullets.erase(bullets.begin() + j);
                        ilosc--;
                    }
                }
            }
            czyKoliduje(player.ruch(StepTime));
        }
        window.clear();
        window.draw(bgSprite);
        //Rysowanie poziomu
        for (int i = 0; i < Level::LEVEL_HEIGHT; i++)
        {
            for (int j = 0; j < Level::LEVEL_WIDTH; j++)
            {
                window.draw(map[i][j]);
            }
        }
        //Rysowanie pociskow
        for (int i = 0; i < bullets.size(); i++)
        {
            window.draw(bullets[i]);
        }   
        for (int i = 0; i < ennemies.size(); i++)
        {
            window.draw(ennemies[i]);
        }
        window.draw(player);
        window.display();
    }
}
//Kolizje
void Engine::czyKoliduje(Vector2f ruch)
{
    FloatRect x = player.getGlobalBounds();
    FloatRect y = player.getGlobalBounds();
    x.left += ruch.x;
    y.top += ruch.y;
    bool kolY = false, kolX = false;
    for (int i = 0; i < Level::LEVEL_HEIGHT; i++)
    {
        for (int j = 0; j < Level::LEVEL_WIDTH; j++)
        {
            if (level.tiles[i][j].tileType != 0)
            {
                if (x.intersects(map[i][j].getGlobalBounds()))
                    kolX = true;
                else if (y.intersects(map[i][j].getGlobalBounds()))
                    kolY = true;
                for (int k = 0; k < bullets.size(); k++)
                {
                    if (bullets[k].getGlobalBounds().intersects(map[i][j].getGlobalBounds()))
                    {
                        bullets.erase(bullets.begin() + k);
                        ilosc--;
                    }
                }
            }
        }
    }
    if (!kolX)
        player.move(Vector2f(ruch.x, 0));
    if (!kolY)
        player.move(Vector2f(0, ruch.y));
}

在容器上调用erase()的所有循环都没有考虑到当您从容器中擦除项目时容器的大小会发生变化。要在容器中正确地循环,同时从中擦除项,应该使用迭代器而不是索引。erase()返回一个新的迭代器,该迭代器指向已擦除项之后的项,因此您可以继续循环。

std::vector<enemy>::iterator i = ennemies.begin();
while (i != ennemies.end())
{
    i->update(player);
    if (player.getGlobalBounds().intersects(i->getGlobalBounds()))
    {
        player.kill();
    }
    bool hit = false;
    for (std::vector<bullet>::iterator j = bullets.begin(); j != bullets.end); ++j)
    {
        if (i->getGlobalBounds().intersects(j->getGlobalBounds()))
        {
            hit = true;
            i = ennemies.erase(i);
            j = bullets.erase(j);
            ilosc--;
            break;
        }
    }
    if (!hit)
        ++i;
}

for (int i = 0; i < Level::LEVEL_HEIGHT; i++)
{
    for (int j = 0; j < Level::LEVEL_WIDTH; j++)
    {
        if (level.tiles[i][j].tileType != 0)
        {
            if (x.intersects(map[i][j].getGlobalBounds()))
                kolX = true;
            else if (y.intersects(map[i][j].getGlobalBounds()))
                kolY = true;
            std::vector<bullet>::iterator k = bullets.begin();
            while (k != bullets.end())
            {
                if (k->getGlobalBounds().intersects(map[i][j].getGlobalBounds()))
                {
                    k = bullets.erase(k);
                    ilosc--;
                }
                else
                    ++k;
            }
        }
    }
}

话虽如此,您可能会考虑使用std::remove_if()而不是手动erase()循环:

template<typename SourceType, typename TargetType>
struct intersectsBounds
{
    TargetType &m_target;
    intersectsBounds(TargetType &target) : m_target(target) {}
    bool operator()(const SourceType &source) const
    {
        return source.getGlobalBounds().intersects(m_target.getGlobalBounds());
    }
};

std::vector<enemy>::iterator i = ennemies.begin();
while (i != ennemies.end())
{
    i->update(player);
    if (player.getGlobalBounds().intersects(i->getGlobalBounds()))
    {
        player.kill();
    }
    std::vector<bullet>::iterator j = std::remove_if(bullets.begin(), bullets.end(), intersectsBounds(*i));
    if (j != bullets.end())
    {
        i = ennemies.erase(i);
        int numErased = std::distance(j, bullets.end());
        bullets.erase(j, bullets.end());
        ilosc -= numErased;
    }
    else
        ++i;
}

for (int i = 0; i < Level::LEVEL_HEIGHT; i++)
{
    for (int j = 0; j < Level::LEVEL_WIDTH; j++)
    {
        if (level.tiles[i][j].tileType != 0)
        {
            if (x.intersects(map[i][j].getGlobalBounds()))
                kolX = true;
            else if (y.intersects(map[i][j].getGlobalBounds()))
                kolY = true;
            std::vector<bullet>::iterator k = std::remove_if(bullets.begin(), bullets.end(), intersectsBounds(map[i][j]));
            if (k != bullets.end())
            {
                int numErased = std::distance(k, bullets.end());
                bullets.erase(k, bullets.end());
                ilosc -= numErased;
            }
        }
    }
}