Game of Life with Flutter

Christian Muehle
Nov 10, 2019 · 7 min read
Photo by Heather McKean on Unsplash

I would like to show you a version of Game of Life build with Flutter. My intention was to get some insights on the following topics:

  • Custom drawing — create your own UI-elements
  • Very basic “game” approach — game loop

About the game

Let’s first start with a brief intro explaining what “Game of Life” is actually about. In case you know the board game called “Game of Life” I have to disappoint you — the game we are building here is a bit different. Below is the summary in my words, feel free to skip this and check the great Wikipedia article directly.

Not the Game of Life we are looking for - By GIPHY

The rules

The game shows a board of cells which can either be alive or dead. Every turn, each cell gets checked and a new state (dead, alive) is calculated based on the current game board. The rules are quite simple — a cell will only change the state based on the following rules:

  1. Any living cell with < 2 live neighbors will be changed to dead in the next round
  2. If a dead cell has 3 living neighbors it will get alive in the next round
  3. Any living cell with either two or three live neighbors (in all directions) will not change the state in the next round
  4. Any living cell with more than three neighbors will die in the next round

The game will run infinitely and every round will introduce a new generation of cells until all cells are dead or spread across the board in a way that they can't interact with other cells according to the described rules above.

Code, just show me the code

Photo by Heather McKean on Unsplash

The complete project is hosted on GitHub. Please note, I’m new to Flutter so please excuse any code smells you might spot:

The start

To start, either create a new flutter project or simply clone my repository. I will skip the project creation, in case you need a helping hand check out the great Flutter starting guide.

Project structure

We can divide the code into three main areas of tasks:

  1. The main widget — gets all parts of the game together
  2. The game logic class — all game rules are applied in here
  3. The drawing department — drawing of the cells is handled in here

If you’re wondering why the code is split up like this, at first I like to separate code by its actual job and secondly I might want to reuse the game logic code (which is pure dart code) for other projects.
For example, we could set up a Game of Life web version using dart and the logic class from the Flutter project…

The main widget

To keep it short, the job of the main widget is to bring everything together and provide sizing information to our drawing department. Most of the code inside the main.dart file is nothing special, nevertheless I would like to point out the more interesting places to get you started:

The first line creates our logic class, it will be used to interact with our game. To get a new board and ensure the app is running in fullscreen during startup we use the initState method.
Thanks to the _game object we can simply call resetWorld() and get a fresh new start. The last method in the code allows the app to toggle the game between running or paused mode, the call to setState ensures that Flutter will update the UI accordingly.
To have something we can start/pause we need a so called game loop. This loop is handled by our logic object (_game) but somehow we have to update our UI after each iteration to make sure our App shows changes. I decided to use a StreamBuilder for this job — with every loop the StreamBuilder gets a notification to update the UI.

You might spot a bit more in the above code. It includes the callback to our toggle methods to start/pause the game and also some size calculation for the cells. I will explain most of it in the following parts.

Game logic

To get the game started we have to fill the world, this job is done by the code below:

The board itself is a simple List of boolean values. The resetWorld function performs the following steps:

  1. Fill the world with dead cells, from zero to worldSize (right now 1024 cells)
  2. Getting a random number of cells up to 50% of the world size, see documentation for nextInt
  3. Mark cells as living until we reached the limit generated in our second step

You might have noticed that the above logic could end up with less active cells as our second step decided. This is due to the fact that the third step doesn’t check if the randomly selected cell is already active, it could happen that we set the same cell active twice.

Ready to go

Our game is ready to start, now we need to take care of the game loop that will update the cells based according to the game rules.

Game updates are handled by the _runTheGame Method. To ensure the loop is running “slow” enough it starts with sleep, our app will wait 350ms before it calculates the next round.

This part might look complicated but it solves a problem that all Game of life implementation face:

How do you handle cells at the edge of the board?

In my app the board has no real edges, if you are on the far right side and go one step to the right you will end up on the first left position. The same for the top or bottom end of the board, if you step over the edges you will end up on the opposite side.
It might remind you of the old Pacman game.
The complete calculation to apply the game rules is done by changing the index inside the array to check all surrounding cells, left, right, top, bottom and diagonal.

The drawing department

Getting the logic on the screen is the job of our drawing department, in this game we don’t require a lot of elements. Everything we need for custom drawing can be found in the code below.

Flutter contains the great and easy to use CustomPainter, the main idea is quite easy, it has two jobs:

  1. Draw the element with the provided size on the given canvas
  2. Decide if you need to draw your element again

Our cells will be represented by a rectangle with rounded edges, the color depends on the cell state. Living cells will be green, dead cells will be orange.
Drawing the rectangle is done by the build in function drawRRect you need to pass a rectangle with size, position and the radius for the edges.

A cell has to be painted again only if:

  • The position or size of the cell has changed, for example, because the user rotated the phone
  • The cell state changed, a living cell died or the other way around

Last puzzle piece is to arrange all cells in a way that our app renders the board, this is done by the code below:

The big idea behind the code is to draw the board row by row based on the calculated sizes.

UPDATE

Since this post I worked quite a bit with Flutter and Flame, right now I’m developing a “real” game from zero to credit screen ;) using Flame and Box2D check out my post below.

Conclusion

First, Flutter is awesome, I tried a lot of cross-platform development tools but I have to admit that Dart and Flutter are easy to start and the provided tooling just works ( I’m using Linux, tested it also on Windows).

Creating custom UI elements is made in a logical two-step implementation, decide what you want to draw and when to redraw.

Game of life itself can be implemented in many ways, for myself it’s always a good way to test out a new platform/language. Besides the technical point of view, I like to watch and see how a randomly created board develops into different patterns or simple fades out or gets stuck in a repeating motion.

If you are curious about all the different shapes/pattern Game of life might generate check out the following resources:

If you want to see an epic version of Game of life:

Thanks for reading

Flutter Community

Articles and Stories from the Flutter Community

Thanks to Nash

Christian Muehle

Written by

Software developer, hobby photograph. Working in the marine industry as a team lead with an international development team

Flutter Community

Articles and Stories from the Flutter Community

More From Medium

More from Flutter Community

More from Flutter Community

More from Flutter Community

Font Features in Flutter

192

More from Flutter Community

More from Flutter Community

Flutter — Shadows & glows

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade