I'm trying to do exactly what this guy is doing but I think he may have less requirements than me because the answers in that post don't seem like they'd work for my game. Let me inline his algorithm so my question is easier to understand:
The easiest solution is to loop from tail to head and set the position of the current to the next segment's position, ie:
segment[i].position = segment[i - 1].position
I think the key difference between our requirements is I want to move each piece less than its own width/height on every tick. For example:
Pretend these squares are aligned horizontally (I drew it unaligned because I think it makes it easier to see what's going on). The red H
is where the head currently is. The red T
is where the tail currently is. The black H'
is where the head should be next tick. So the snake is moving right to left. If I use the algorithm described above, won't the segments overlap or start driving apart? Let me play it out step by step:
The result of this would become:
What algorithm can I use to make sure that all the pieces move at the same speed and stay the same distance apart from each other?
I'll give my idea, but I'm skeptical of it because my research doesn't show anyone else using this:
Each segment will store it's coordinates and its direction. EG: [[50, 50, LEFT], [100, 50, LEFT]]
. The head is index 0, the tail is index 1. The speed at which the snake moves is 10, even though the segments are 50x50.
Each tick I'll do this:
nextDirection
variable with the direction that was pressed. Otherwise, nextDirection
is whatever it was last tick. In this example, lets assume someone pressed UP
.[[40, 50, LEFT], [90, 50, LEFT]]
nextDireciton
. EG: [[40, 50, UP], [90, 50, LEFT]]
Does this algorithm seem like it would work? Part of the reason I'm asking is because it's more complicated than the other guy's algorithm so I feel like I'm doing something wrong. And also, the more I think about his algorithm, the less it seems like it can work.
Pretend each segment of the snake is a 20x20 pixel rectangle. Each tick, I want the head to move 5 pixels in some direction. How do I make sure all the segments stay touching each other?
@Rafe's description below in a comment is:
Consider the ordered set of locations occupied by the snake at step
t
, with the leftmost being the tail and the rightmost being the head:{A, B, C, D, E}
. At stept+1
, the ordered set of locations occupied by the snake is{B, C, D, E, F}
where the tail has moved fromA
toB
and the head has moved fromE
toF
.
And I don't think this algorithm works because:
Yes but if the width of
A = B = C = D = E = F = 20px
. Shifting{A, B, C, D, E}
so that it becomes{B, C, D, E, F}
just added 20px to the right side and removed 20px from the left side. Doesn't this mean he moved 20px, not 5px? I want to move 5px, not 20px If you're saying that's accomplished with your suggestion, please explain how. I don't see it.
I know you're ignoring the grid but what about making the distance the snake moves forward some number that factors your big block size evenly?
Let's say that you're moving forward only half of the width/height of your block.
Now you can optimize a bit.
n
, that runs throughout the game.n = 0
). Let's call this snake_even
.n = 1
), create the blocks that comprise the next snake by moving them all forward 1/2 unit. Let's call this snake_odd
.snake-even
or snake_odd
, but you can create snake_even(n+2)
from snake_even(n)
, or snake_odd(n+2)
from snake_odd(n)
just by changing the head to the new position and writing over the tail.snake_xxxx
you're on, and then add the length to the other one.If you want to move forward only 1/5th of the height, you'd do the same thing, but you'd have five arrays to keep track of instead of two.
Additional info based on your added example (20x20 px segments moving 5 px each step):
Take a 4-segment snake moving to the right. Segment sizes are 20x20 px, and they move 5 px per move. I'll define the snakes as a list of coordinates (x, y)
. I'll mark the head with 'H' and the snake will cycle by moving right in the list, cycling back to the beginning if needed.
// n = 0
snake_0 => H(60, 0), (40, 0), (20, 0), (0, 0)
// Snake is moving to the right.
// n = 1 -- construct snake_1 from snake_0 and display that one (n % 4 = 1)
snake_1 => H(65, 0), (45, 0), (25, 0), (5, 0)
// n = 2 -- construct snake_2 from snake_1 and display that one (n % 4 = 2)
snake_2 => H(70, 0), (50, 0), (30, 0), (10, 0)
// n = 3 -- construct snake_3 from snake_2 and display that one (n % 4 = 3)
snake_3 => H(75, 0), (55, 0), (35, 0), (15, 0)
// n = 4 -- Now just move the head, and re-use all but the tail of snake_0
snake_0 => (60, 0), (40, 0), (20, 0), H(80, 0)
// n = 5
snake_1 => (65, 0), (45, 0), (25, 0), H(85, 0)
// n = 6
snake_2 => (70, 0), (50, 0), (30, 0), H(90, 0)
// etc.
Now one thing I forgot to take into account was the direction each segment needs to move. That could be stored right alongside the coordinate. But I think that part you probably understand already.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With