I am currently working on a Snake game, everything functions as it should except the vector containing the snake body positions. The head of the snake should be the only initial element and after an apple has been eaten a new body part is added along with a trailing tail.
To move the snake body positions so it looks like they are part of the snake I use std::shift_right which works very well except for the first body part added. When the first part is added it is always inside the head/front of the vector. This makes it look like the snake has no growth/parts that follow.
As soon as the second apple is eaten the snake gets a ‘tail’. The snake_body vector has now 3 elements while visually only having 2 on the game screen.
One apple has been eaten (snake_body is 2 long) but no tail
Two apples have been eaten (snake_body is 3 long) but has 1 part following instead of 2
How do I fix this?
(Thankyou in advance)
Related sample code:
std::vector <SDL_Point> snake_body = { SDL_Point(_PLAYER_START_POS) };
void Player::Movement()
{
switch (active_valid_input)
{
case SDLK_UP:
snake_body.front() = snake_body.front() + _MOVEMENT_UP;
break;
case SDLK_DOWN:
snake_body.front() = snake_body.front() + _MOVEMENT_DOWN;
break;
case SDLK_RIGHT:
snake_body.front() = snake_body.front() + _MOVEMENT_RIGHT;
break;
case SDLK_LEFT:
snake_body.front() = snake_body.front() + _MOVEMENT_LEFT;
break;
default:
break;
}
std::shift_right(snake_body.begin(), snake_body.end(), 1);
}
void Player::AddSnakePart() noexcept{
snake_body.push_back(snake_body.back());
}
>Solution :
You need to break up your movement, such that the shift happens between calculating the next head position, and assigning that position to head. At the moment your movement function leaves the head part in a moved-from state.
void Player::Movement()
{
SDL_Point next_head;
switch (active_valid_input)
{
case SDLK_UP:
next_head = snake_body.front() + _MOVEMENT_UP;
break;
case SDLK_DOWN:
next_head = snake_body.front() + _MOVEMENT_DOWN;
break;
case SDLK_RIGHT:
next_head = snake_body.front() + _MOVEMENT_RIGHT;
break;
case SDLK_LEFT:
next_head = snake_body.front() + _MOVEMENT_LEFT;
break;
default:
break;
}
std::shift_right(snake_body.begin(), snake_body.end(), 1);
snake_body.front() = next_head;
}
Aside: I would extract that switch into a function:
SDL_Point Player::Direction()
{
switch (active_valid_input)
{
case SDLK_UP: return _MOVEMENT_UP;
case SDLK_DOWN: return _MOVEMENT_DOWN;
case SDLK_RIGHT: return _MOVEMENT_RIGHT;
case SDLK_LEFT: return _MOVEMENT_LEFT;
}
}
void Player::Movement()
{
SDL_Point next_head = snake_body.front() + Direction();
std::shift_right(snake_body.begin(), snake_body.end(), 1);
snake_body.front() = next_head;
}