0

I'm trying to make a snake game and maybe this error is one of possible. So when I'm debugging and stepping over then I getting link to exception in header file of vector and in exception code wrote that vector has invalid subscript. (Error cause can called by vector bodyPart). The compiler message:

Unhandled exception at 0x00007FFA227EA799 in snake.exe: Microsoft C++ exception: std::out_of_range at memory location 0x00000052FA7CDFD0.

Snake::Snake(RenderWindow& window)
{
    bodyPart.setPosition(window.getSize().x / 4, window.getSize().y / 4);
    bodyPart.setSize(Vector2f(20.f, 20.f));
    bodyPart.setFillColor(Color(0, 0, 0));
    body.push_back(bodyPart);
}
//Sets default parameters
void Game::restart(RenderWindow& window)
{
    for (int i = 0; i < snake.body.size() - 1; i++)
    {
        snake.body.pop_back();
    }
    snake.bodyPart.setPosition(window.getSize().x / 4, window.getSize().y / 4);
    snake.body.push_back(snake.bodyPart);
}
//Updates game
void Game::tick(RenderWindow& window)
{
    if (snake.body.at(0).getPosition().x == fruit.fruitX && snake.body.at(0).getPosition().y == fruit.fruitY)
    {
        fruit.fruitX = fieldLCorn + rand() % fieldX * fieldY;
        fruit.fruitY = fieldLCorn + rand() % fieldY * fieldX;
        ui.score++;
        snake.body.reserve(1);
        snake.body.push_back(snake.bodyPart);
    }
}
void Game::moveSnake()
{
    switch(dir)
    {
    case 1:
        snake.body.push_back(snake.tail);
        snake.body.at(0).move(0, snake.body.at(0).getPosition().y + 10);
        snake.body.pop_back();
    case 2:
        snake.body.push_back(snake.tail);
        snake.body.at(0).move(0, snake.body.at(0).getPosition().y - 10);
        snake.body.pop_back();
    case 3:
        snake.body.push_back(snake.tail);
        snake.body.at(0).move(snake.body.at(0).getPosition().x + 10, 0);
        snake.body.pop_back();
    case 4:
        snake.body.push_back(snake.tail);
        snake.body.at(0).move(snake.body.at(0).getPosition().x - 10, 0);
        snake.body.pop_back();
    }
}
void Game::countCollision(RenderWindow& window)
{
    //Is snake met border
    if (snake.body.at(0).getPosition().x > 300) restart(window);
    if (snake.body.at(0).getPosition().y > 300) restart(window);
    if (snake.body.at(0).getPosition().x < -300) restart(window);
    if (snake.body.at(0).getPosition().y < -300) restart(window);
    //If snake eats itself
    for (int k = 0; k < snake.body.size() - 1; k++)
    {
        if (snake.body.at(0).getPosition().x == snake.body.at(k).getPosition().y && snake.body.at(0).getPosition().y == snake.body.at(k).getPosition().y)
        {
            restart(window);
        }
    }
}
void Game::render(RenderWindow& window)
{
    for (int i = 0; i < snake.body.size() - 1; i++)
    {
        window.draw(snake.body.at(i));
    }
}
Vlad
  • 3
  • 2
  • 1
    Have you tried to catch the crash in the debugger to see when and where in your code it happens? What is the index used? What is the size of the vector? And what vector are you talking about? Please [edit] your question to show a [mcve], with emphasis on both the minimal and complete bits. And if it's reproducible then that's a plus. – Some programmer dude May 31 '20 at 17:27
  • 1
    On another note, call `srand` only *once*. By putting it in the `Fruit` constructor each and every fruit object you create will reset the seed. If you do it twice (or more) within a single second then the seed will be set and reset to the same value (as `time` usually returns a value with second resolution). – Some programmer dude May 31 '20 at 17:30
  • ***Microsoft C++ exception*** that means you likely are using Visual Studio and you can have it break at the exact line this happens to inspect where this happens and why. – drescherjm May 31 '20 at 17:32
  • I'm tried to catch line which makes error but debuggers only links to exception in header file. Ok I'll edit. – Vlad May 31 '20 at 17:32
  • 1
    Change the "Stack Frame" combo box (on the toolbar of Visual Studio) to your code. That will show you the line of your code that caused the issue. – drescherjm May 31 '20 at 17:33
  • [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/5910058) – Jesper Juhl May 31 '20 at 17:33
  • `std::out_of_range` is a *huge* hint. Look at everything that indexes into arrays or containers and validate that they are all within bounds. – Jesper Juhl May 31 '20 at 17:35
  • Where's "Stack Frame"? I can't find it.(Btw i tried to toggle it in list of toolbars). – Vlad May 31 '20 at 17:59
  • In VS2019 You need the "Debug Location" toolbar enabled and you need to be debugging. – drescherjm May 31 '20 at 20:34

3 Answers3

0

For what I can see here, the problem might be the

snake.body.at(0)

That you are using inside your code a lot of times, when maybe the body has no elements, and so there is no 0's element

Alberto Sinigaglia
  • 12,097
  • 2
  • 20
  • 48
  • I put 1 in `at()` but this does't help. And I think that vector has elements because I has putted element: `body.push_back(bodyPart);` – Vlad May 31 '20 at 18:03
  • 1 won't obviously help, instead you should check in your code that that "bodyPart" can be removed in some case @Vlad – Alberto Sinigaglia May 31 '20 at 19:49
  • 1
    ***I put 1 in at() but this does't help.*** If anything that would make it worse. – drescherjm May 31 '20 at 20:51
0

In your Game::render() function the condition of the loop will obviously give an 'out-of-bound' error because in for (int i = 0; i < snake.body.size() - 1; i++) it will try to access 1-past the last element. So you should either check for <= or remove the -1 (advised).

Hack06
  • 963
  • 1
  • 12
  • 20
0

So I solved problem by adding a head section in body container and using constructor without parameters, also i deleted checking of vector size where it's not needed (no). Here is my new code:

Snake::Snake()
{
    body.reserve(4);
    head.setPosition(400, 400);
    head.setSize(Vector2f(20.f, 20.f));
    head.setFillColor(Color(0, 0, 0));
    body.push_back(head);
    for (int i = 0; i < 3; i++)
    {
        bodyPart.setPosition(body.at(i).getPosition().x - 20, body.at(i).getPosition().y - 20);
        bodyPart.setSize(Vector2f(20.f, 20.f));
        bodyPart.setFillColor(Color(0, 0, 0));
        body.push_back(bodyPart);
    }
}
void Game::restart()
{
    for (unsigned int i = 0; i < snake.body.size(); i--)
    {
        snake.body.pop_back();
    }
    snake.head.setPosition(400, 400);
}
void Game::tick()
{
    moveSnake();
    if (snake.body.at(0).getPosition().x == fruit.fruitX && snake.body.at(0).getPosition().y == fruit.fruitY)
    {
        snake.body.reserve(1);
        for (unsigned int i = snake.body.size() - 1;i > 0;i--)
        {
            snake.body.at(i).setPosition(snake.body.at(i - 1).getPosition().x - 20, snake.body.at(i - 1).getPosition().y - 20);
        }
    }
    countCollision();
}
void Game::moveSnake()
{
    switch(dir)
    {
    case 1:
        snake.body.push_back(snake.bodyPart);
        snake.body.at(0).move(0, snake.body.at(0).getPosition().y + 10);
        snake.body.pop_back();
    case 2:
        snake.body.push_back(snake.bodyPart);
        snake.body.at(0).move(0, snake.body.at(0).getPosition().y - 10);
        snake.body.pop_back();
    case 3:
        snake.body.push_back(snake.bodyPart);
        snake.body.at(0).move(snake.body.at(0).getPosition().x + 10, 0);
        snake.body.pop_back();
    case 4:
        snake.body.push_back(snake.bodyPart);
        snake.body.at(0).move(snake.body.at(0).getPosition().x - 10, 0);
        snake.body.pop_back();
    }
}
void Game::countCollision()
{
    if (snake.body.size() >= 5)
    {
        //If snake eats itself
        for (unsigned int k = 1; k < snake.body.size(); k++)
        {
            if (snake.body.at(0).getPosition().x == snake.body.at(k).getPosition().y && snake.body.at(0).getPosition().y == snake.body.at(k).getPosition().y)
            {
                restart();
            }
        }
    }
}
void Game::render(RenderWindow& window)
{
    for (int i = 0; i < snake.body.size(); i++)
    {
        window.draw(snake.body.at(i));
    }
}
Vlad
  • 3
  • 2