How to Create a 2D Snake Game in Flutter

Learn how to use Flutter as a simple game engine by creating a classic 2D Snake Game. Get to know the basics of 2D game graphics and how to control objects. By Samarth Agarwal.

Leave a rating/review
Download materials
Save for later
Share

The Flutter framework lets you build apps for Android, iOS, web and even desktop platforms, all using a single codebase. While many big companies use Flutter for their thriving apps, including Google Pay and Alibaba Xianyu, not many are exploring game development with Flutter. That’s just what you’ll do in this tutorial.

Since Flutter is capable of rendering UI at up to 60 FPS, you’ll exploit that capability to build a simple 2D Snake game in Flutter.

Along the way, you’ll learn how to:

  • Use Flutter as a game engine
  • Move objects
  • Control movement
  • Build game UI
  • Add game elements
Note: This article assumes that you know the basics of the Flutter framework including common widgets and their properties. This also assumes that you are comfortable with the Dart programming language and conventions. To learn about the basics of Flutter and Dart, please checkout Dart Apprentice and Flutter Apprentice books.

Now, it’s time to familiarize yourself with the starter project.

Getting Started

Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.

Unzip the downloaded file and open it with Android Studio 4.1 or later. You can use Visual Studio Code instead, but if you do, you’ll need to tweak some instructions to follow along.

Click Open an existing Android Studio project and choose the starter folder from your unzipped download.

Run the flutter create . command in the starter folder to generate the android and ios folders. Next, download your dependencies by double-clicking pubspec.yaml on the left-side panel, then clicking pub get at the top of your screen. To avoid problems, delete the test folder, which Flutter generated when you executed the flutter create . command.

Finally, build and run to see this:

Starter project on iOS Simulator

The starter project sets up the playing field. You’ll add UI elements to it as you build the game. The starter project also provides several useful utility methods so you can focus on the bigger picture: writing the game. Here are the pre-built functions you’ll find in the starter project, along with how to use them:

  • roundToNearestTens(int num): Rounds off the passed integer argument to the nearest step value. This allows you to get the exact next position that’s step units away from the current position on an imaginary grid.
  • getRandomPositionWithinRange(): Generates a random position on the screen within the bounds of the play area. You’ll use this function to spawn a new snake and food for the snake.
  • showGameOverDialog(): Displays a styled dialog pop-up when the Snake collides with any of the boundaries of the play area. This dialog displays the user’s score and a button to restart the game.
  • getRandomDirection([String type]): Randomly returns one of the four directions: up, down, left or right. You primarily use this function to move the Snake in a random direction when it spawns. It optionally takes an argument that specifies whether you want the random direction it returns to be horizontal or vertical.
  • getRandomPositionWithinRange(): Returns a random position on the screen within the play area. It ensures that the random position lies on the grid along which the snake moves.
  • getControls(): Implements ControlPanel, a widget that displays four circular buttons on the screen to control the movement of the snake.
  • getPlayAreaBorder(): Draws a border along the edge of the screen to represent the play area where the screen moves.

Using Flutter as a Game Engine

A game engine is a suite of tools and services that helps game developers build games. They handle a lot of different things like graphics, sounds, artificial intelligence, user input, networking, and much more. Flutter can handle most of these things, as well. As a Flutter developer, you have access to a whole world of Dart plugins. Plus, if one doesn’t exist, you can always code it yourself.

To start with Flutter as a game development engine, you’ll use the rendering capabilities of the framework to animate game objects like the snake, food, and game score. In this case, you’ll use a timer to regenerate the UI 60 times per second and display a snake on the screen. By rendering the snake at up to 60 FPS while changing its position, you can achieve a pretty smooth moving animation effect.

Game engines like Unity work in a similar manner. The difference here is that pushing the limits of the framework too much could end up in an app that needs a lot of resources. However, while testing this game, Flutter performed amazingly well without heating the device at all.

Drawing the Snake

Your first step is to create the snake. You’ll start with the Piece widget in the starter project, which renders a colored circle on the screen. With this widget, you’ll draw the snake, piece-by-piece, as well as the snake food.

Before you draw the snake, however, it’s worth taking a moment to understand the basics of 2D rendering with Flutter.

The Basics of 2D Rendering

To render anything that’s constantly changing its position on the screen, you’ll need to use widgets like Stack and Positioned. Given the x and y coordinates, these widgets can place child widgets anywhere on the screen.

The most important thing to keep in mind is that you’re working on a mobile app, which needs to run on devices with all sorts of screen sizes and aspect ratios. That means you can’t hard code any of the dimensions of the game field. Instead, you’ll use MediaQuery to get the width and height of the user’s screen, then calculate position based on these values.

For example, here’s a simple code snippet that declares variables, then assigns the screen’s width and height to them.

final screenSize = MediaQuery.of(context).size;
final screenWidth = screenSize.width;
final screenHeight = screenSize.height;

In the code snippet above, the MediaQuery inherited widget is used to get the current device’s screen’s width and height. This requires the content to be passed and therefore, we have this code right inside the build() itself.

Now that you know how you’ll place objects on the screen, it’s time to draw that snake.