The game will start with a simple hello menu. Then, the grid and score will be displayed on the LCD screen.
User input:
Any functionality of the game will be implemented both ways, either by interpreting screen touch or joystick input.
Modules used:
Components will be connected as in the below block diagram:
Screen is using 3V3 for logical 1 while Arduino UNO uses 5V as pin output. Thus voltage dividers were added in order to prevent screen damage.
To obtain a good ration, two pairs of resistors were used:
Arduino SPI interface is shared between display and touchscreen.
From the module, only the left joystick is used, thus only a couple of pins are connected.
Component | Shop Link | Datasheet Link |
---|---|---|
TFT LCD 2.8” | eMAG Product Page | Datasheet & info |
Arduino Uno | eMAG Product Page | Datasheet |
Joystick Module | eMAG Product Page | Datasheet |
Resistors | eMAG Product Page | Datasheet |
Adafruit_GFX.h
Adafruit_ILI9341.h
XPT2046_Touchscreen
EEPROM.h
avr/sleep.h
Code splits itself in two main components:
→ At first, a starting menu is displayed and on button press, the game starts.
→ While playing, possible moves are LEFT
,RIGHT
, UP
and DOWN
and depending on the direction the grid changes.
→ If a tile with value 2048
is reached, the game is considered to be won and a win screen is displayed.
→ Best score is updated if necessary and start of a new game is possible on button push.
→ If no more possible moves are available, that is grid is full and no tiles can coalesce anymore, game is considered to be lost.
→ Best score is updated and lose screen is available.
→ However, user has possibility of performing an Undo
, which could lead to possibility of playing longer if a convenient tile is generated.
→ At any point in the game, 3 undos are possible. If more are requested, state is not changed.
→ On every move, if grid has changed, a new tile appears in a random position.
→ Bear in mind that if grid does not change, no tile is added in order to avoid fake moves.
→ Value of new tiles is either 2
or 4
, but they are added with different probabilities.
→ 2
appears in 8 out of 10 case, while 4
otherwise.
→ This ensures a longer game.
→ However, this might mean more trials when performing an undo if game was lost.
→ random()
function was used to generate both tile values and tile position.
→ Tile position is randomly chosen from list of free positions.
→ At game start, randomSeed is initialized with analog value of a floating pin in order to avoid predictibility.
→ The XPT2046
actually does not return pixel coordinates of touch.
→ Thus remap using map
was needed in order to get from a scale of (0, 4095) to screen pixel dimensions.
→ For a cleaner code, Grid
class was implemented as a wrapper over a simple 4×4 matrix.
→ This way, overloaded ==
operator and copy constructor made saving states for undos and performing undo moves easier.
User can choose to use touchscreen or joystick.
In loop function, both variants are polled. Interruptions could not be used because ISR function would have been too complex. Thus I chose polling approach, taking into consideration that playing implies rather continuous moves.
→ Information is not displayed ,on every frame'. Thus, throughout the code I used to display different screens once and maintain them unchanged as much as possible.
→ SPI protocol is fast, but clearing the whole screen and overwriting all pixels is by far visible with human eye. Thus animations that can be implemented cannot be too fast.
→ As mentioned above, rerendering is avoided as much as possible. Thus, when screen changes, tile are rendered only if they have different value than before.
→ When rendering tiles, color is chosen based on their value. In order to perform this efficiently, ILI9341 provided colors are stored in an array and bitwise dividing is used in order to find idx = log2(val).
→ EEPROM.update
was used instead of EEPROM.write
in order to preserve non-volatile memory lifetime.
Arduino
uses a 10-bit ADC in order to map analog read values from pins used for joystick's Vrx, Vry and maps values between 0 and 1023XPT2046
touchscreen controller uses a 12-bit ADC to convert measured voltage to a value in range 0 - 4095This project was a good opportunity to see how theoretic notions work in real life, applying them the make something entertaining.