(I can copy this over to your original question if you'd like to undelete that one and delete/close this one instead)
I'd solve this by storing an array of the grid points the snake head has run through, and the next point it's on its way toward.
Then we'll store a progress variable between 0 and 1, that represents how far the snake has progressed from its old position to its new position.
We'll number our snake parts from 0 for the head up to snakeSize - 1
for the last tail segment. In our positionHistory
array, 0 will be the point the head is moving toward now, 1 will be the point the head just left, and snakeSize
will be the point the last tail segment just vacated.
We can update the state like so:
progress += deltaTime / secondsToCrossOneTile;
if (progress >= 1.0f) {
// TODO: Handle activating a new tail segment here
// when finishing the previous growth phase.
// TODO: Handle eating a pellet here and beginning a new growth phase.
for (int i = snakeSize; i > 0; --i) {
positionHistory[i] = positionHistory[i - 1];
}
positionHistory[0] = PickNextPoint();
progress -= 1.0f;
}
(You could also store your history as a circular buffer, and just shift the starting offset instead of copying all the data over one notch)
Now every frame we can run through each piece in the list, using this progress value as an interpolation weight between its old position and the new position.
for(int i = 0; i < snakeSize; i++) {
snakePart[i].position = lerp(positionHistory[i+1], positionHistory[i], progress);
}
When you want to add a segment to the snake, you place it at the position of the last tail segment, and leave it stationary there until the next time we hit our progress >= 1.0f
condition. Then you append it to the snakePart
collection and extend the position history an extra notch.