In the “Solving Problems” post series, I talk about the main challenges I have faced when building a software. This time, I’ll talk about how I found out that snakes are made of Lego and fast by nature.
Basically, I made a clone of the classic Snake. This article can be understood even by those who don’t know the C language, which was used to create the game. These were the main challenges I came across:
Snake’s Movement
At first, movement is simple in a Snake Game. The snake moves by itself, while the player controls the direction in which it moves. But it’s not possible to move it in the opposite direction to the current. For example, from left to right or vice versa. So if the snake is moving upwards and the player presses the down arrow key, it will continue to move upwards. In that case, she/he should choose left or right to make it change direction.
I mentioned that the player controls the direction in which the snake moves. Being more precise, she/he controls only the direction of the snake’s head. Indirectly, the movement of the snake’s body is influenced by the player, since the body follows the head.
Snake’s Body
It’s pretty simple to move the snake’s head, it’s the same as to move a square on the screen. However, to move the snake’s body is more complicated. To do that, it’s necessary to break the snake’s body down into independent parts, which are similar to the head. I’ll call it pieces. That is, the snake’s body is compound by a row of pieces. Thus, a piece must follows the one in front of it to move the snake. From this concept, I found the following solution:
Grid-based movement. It means that, at each frame, the snake moves a step on the grid, which is a way to limit the snake movement on the screen.
The gap is the space between two snake’s pieces. It doesn’t interfere with the game functionality, it only exists for aesthetic reasons. If the gap was equal to 0, the snake’s body would be uniform, but the pieces would still exist, it just wouldn’t be possible to see them.
Unlike the gap, the step is essential. It sets the size of each square on the grid and the snake’s speed. Its measure is equal to the sum between the width of a snake’s piece (they are all equal) and the gap.
snake->step = snake->head.width + snake->gap; // Just to illustrate
Now that the concept is contextualized, let’s go to the application:
Those 4 stages happen in 1 frame. The first stage represents the state of the snake at the end of the previous frame. In the second stage, the player’s input has been read and the snake’s head position has been changed. From the third stage, each snake’s piece takes the previous position of the one in front of it. The last stage represents the current state of the snake, which is displayed on the screen at the end of the frame.
Frame Rate
This one gave me a headache too. Being straight, the game runs at 15 frames per second. Why so low? As I explained before, the snake moves 1 step per frame, which is equal to 15 steps per second. Supposing that each step’s length is 30 pixels, it means that the snake moves 450 pixels per second. If the length of the screen is equal to 1024 pixels, then the snake travels almost HALF of the screen in 1 second. It’s pretty fast. If the frame rate was 30 fps, the snake’s speed would be doubled. It would be game over even before the player touches the keyboard.
int pixels_per_sec = FPS * snake->step; // Just to illustrate
A way to compensate the frame rate increase would be to reduce the step’s length. However, to do that, it’s necessary to reduce the size of the snake’s head (and the pieces), which would make the snake very small, because 30x30 pixels is little enough for a 1024x768 resolution screen.
Finally, some people could think that the snake is too fast and they could want to decrease the frame rate. I even agree, but there’s a problem. By decreasing the frame rate too much, the responsiveness of the game is affected. It means that the time interval between the moment at which the player presses a key and the moment at which the snake’s movement is shown on the screen is greater.
It creates a delay, which is perceived when a sequence of keys is pressed.
So 15 fps was the middle ground that I found.
Conclusion
Those were the major challenges that I faced when building this game. All of them related to the snake’s movement. It was fun to solve them.
Certainly there are other possible solutions, leave a comment if you have some idea. If you want to see how I solved the minor challenges or how I implemented this game, just take a look at my GitHub.