Block Puzzle — Almost Playable
Welcome to another article on building a block puzzle. This is a series of articles that describe the process taken to develop a game similar to Tetris (you can find all parts of this series at the end of the article).
In the previous article, we developed the base model for our game. In this article, we will be creating the UI for the game. The UI will use the model previously developed to make a playable game. It will not be the complete game, but having something you can use and play with enables faster feedback. We need feedback to know if the model is easy to use (it should be, because we wrote it using Test Driven Development), but we also need feedback on what’s the next functionality that we should develop. I prefer to do development in small steps and collect feedback as I go, even when I am doing it alone.
Context
When we started this project, we said that we wanted to use the Humble Object pattern. The goal was to make the UI code as simple as possible and to not have to test the Flutter framework. I believe we should strive for a middle ground: we should test the UI without the model, but not the appearance of the UI. Testing a UI is always complicated, but if we reduce it to a simple Humble Object and use a fake model, we can manually verify the UI and then have all the logic live outside the UI.
Preparing the code
To achieve this, the first step is to clean up the house a little bit. You have probably heard about refactoring, but it is a word that has been used and abused. I believe that refactoring has two places in our development cycle. The first place is in our normal TDD cycle, where we refactor our code when all the tests pass. The second place is in preparation to develop a new feature. For me, this is the only time it makes sense to refactor the code: we have something new to develop, and we need to adapt the code’s design to make it a better fit. This is the first step we are going to take.
When we developed the Unit tests for the Game engine, we were using the output of the toString
method to verify the state of the game. The first step was to turn the Board State into an object that we could use the UI. To that end, I refactored the code and then changed the tests to use the new method.
Building a rough UI
The next step was to create the first version of the UI. I kind of managed to do that, but it left a bad taste in my mouth in the sense that I had no tests for anything. I want to be able to test something and to separate the concerns better.

Rough UI of the game, just some squares falling from the top and landing in a column
Extracting state management
To do that I used Flutter’s ChangeNotifier
. The goal is to have all the information regarding state outside the UI and make the UI a true Humble Object. The first step was to carve out all state information from the game_ui. The next step was to actually build a unit test for the new notifier and give it a proper name.
This is still not a game
While the application seems to be a game when you start it, I would not call it a game. You can play: you can just stare at it. There is no fun in that! 😊

Animation of the game playing, with al the squares pilling up.
Add buttons to move the pieces
What we are missing from having a very basic game is the possibility of moving pieces on the board. To do that, I added some buttons at the bottom of the game and also implemented a keyboard listener to ensure that we can play with the keyboard on platforms that have it.
This revealed a logic problem: our game was allowing us to move and rotate the current piece after the game was over. I added some unit tests and the corresponding logic to prevent it.
Now we have something that starts to look like a game we can actually play.

Capture of the game play with controls.
As the final step in this round of changes, I saw some duplication in the code that checked if a piece fit the board. Nothing a small refactoring, supported by the unit tests couldn’t fix easily.
Next Step
There are several steps I can take next: I can add more pieces to make it more interesting, or I can add the detection of complete lines so that we can remove them so that we can play the game for a longer time. I will probably start by detecting full lines and eliminating them. The game also needs a pop of color! 🙂
As usual you will find a tag in GitHub with the state of the project at this point.
Articles in the series: