The challenge is to recreate the nostalgic snake game — the one we played on our Nokia phones for hours! This Snake II app in Flutter is versatile and can be run on pretty much any platform.
Let’s learn and understand the steps I followed along the way -
- Approach: To determine the snake's moveable area and position
- Movement: Automatically move the snake
- A Growing Snake: When the snake eats food it expands its length
- Food: Randomly appears on the screen
Here I’m taking the Matrix approach to solve this and determine the snake position by (x, y) coordinates. Firstly, let’s decide the number of columns and rows in the matrix and the size of each cell which is a square.
So, our width and height of the snake moveable area would be,
width = xcount * cellSize and height = ycount * cellSize
totalCells = xcount * ycount
For instance, I can generate food position by getting a random number between 0 to totalCells, then I can use that position to convert into offset. We are going to use Widget Stack and Position to Rendering our Snake and Food on the screen.
The snake is just a list of coordinates, the length of this list will determine the length of the snake, we can define each coordinate as one snake’s body, and then we can simply render the snake according to their coordinate using the Position widget.
Let’s define the snake body:
Here direction is used to save the current direction of each snake body moving at the moment. We can define the initial snake:
Here we are using the getOffsetforPos function to get offset by position:
This step will give us the center offset for the given position in the matrix.
Moving ahead, we can now render this:
Here getSnakeBody will get an appropriate snake body based on where they are, we know the front of the snake should be the head and the end should be the tail, hence it looks more like a snake than just a square.
Therefore, in order to make it seem right, we rotate the head and tail in the appropriate directions.
NOTE: You can skip this part and simply retain it as a square container with a width and height of 16.
I have defined these body parts already in a different file, you can find them in the repo and openMouth. It basically determines if an open mouth snake head widget should be used in place of the head.
Just like how we rendered the snake using position and offset, we can do the same for Food.
Let’s also define Food
Here count keeps track of how much food the snake has eaten.
We assign position zero initially because we are going to change that before the game starts
Food food = Food(position: 0, offset: Offset.zero);
Now we can render the Food on screen
We must determine the direction in which the snake is moving in order to determine its next position.
For example, if I take the initial snake positions have [1,2,3,4,5,6] that is moving in the right direction then we will add the next position to the last of our array because it’s moving in the right next position will be 7 so we add it at the end and remove the first so it becomes [2,3,4,5,6,7]
Here it’s very important to calculate the next position properly depending on the direction it’s moving.
We can have an enum for Direction:
We can also have an initial function to initiate all our variables.
In order to actually move the snake, we must use the Timer.periodic, which takes a callback function and a duration. Here, we pass the updateSnake function with a time of 300 milliseconds. It, thus, calls the updateSnake function every 300 milliseconds.
updateSnake function calculates the next snake position depending on where the current snake’s last element in the list is also here snake can move one end to another end lets consider the matrix of 4*4 and the snake size is one and it is in the 15th cell and moving down
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
So, if it’s moving down then the next position of that snake should be 3, we can calculate this using xcount, ycount and totalcells
Now that we have a method to update the snake's next position, we can use Timer.periodic so that snakes start moving every 300 milliseconds.
Putting it all together in one method,
Voila, the snake can now move! But the snakes keep moving forever in the same Right direction we initialized in but we can change this by incorporating the use of touch drag and keyboard arrows to change the snake direction.
Changing Snake direction:
We can change the direction of the snake using GestureDetector widget, which we can used to detect drag directions of both touch and the mouse, although we can use the mouse on the web we can use the keyboard for input using RawKeyboardListener widget and change the direction by ARROWS or AWSD keys. Now let’s wrap our Snake rendering widget
Perfect! The snake is now able to change directions when the arrow keys are pressed or when we drag. The point of the game is to eat as much food as possible, so we simply display the score using the Text widget.
Combining all of the pieces with the automated movement, arrow keys, touch or mouse drag, food, and score, we now have a fully working snake game. The game is now fully operational!