How I Rebuilt the OG Snake Game using Flutter

With code snippets, work-in-progress screenshots and a complete app demonstration, this blog can be your go-to guide if you want to build a snake game using Flutter that works on almost all platforms.
Oct 4, 2022

Getting Started

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

Approach:

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.

Snake:

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.

Screenshot of the Snake Game

Food:

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

Automatic Movement:

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!

You can play this game here Live: https://clasicsnakegame.web.app/#/

You find the code here: https://github.com/hemanthkb97/snake_game_clasic