2048 on LCD minigame

Introduction

  • This is a proposed implementation for the classic 2048 game using Arduino Uno and peripheral devices.
  • Purpose:
    • for developer: exercising basic concepts of programming microcontrollers
    • for users: entertainment
  • Motivation:
    • 2048 is my favorite arcade game as it needs the right combination of thinking and luck to make it entertaining enough to be relaxing while developing basic strategies
  • Game functionalities:
    • classical 2048 game with score tracking, high score tracking and GoBack option

Overview

The game will start with a simple hello menu. Then, the grid and score will be displayed on the LCD screen.

User input:

  • swipe on the tactil screen
  • joystick movement
  • joystick button push

Any functionality of the game will be implemented both ways, either by interpreting screen touch or joystick input.

Modules used:

  • Arduino Uno
  • 2.8 inch, 320×240 LCD TFT touchscreen
  • Dual-axis analogic joystick

Components will be connected as in the below block diagram:

Hardware Design

Electrical scheme

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:

  • 560 ohm - 1kohm
  • 4k1 ohm - 10 kohm

Pin configurations

TFT Screen - Arduino

Arduino SPI interface is shared between display and touchscreen.

  • VCC - 5V
  • GND - GND
  • LED - 3V3
  • CS - D8
  • RESET - D9
  • MOSI - D11 (shared)
  • SCK - D13 (shared)
  • MISO - D12 (shared, optional)
  • T_CS - D7
  • T_CLK - D13 (shared)
  • T_DIN - D11 (shared)
  • T_DO - D12 (shared)
  • T_IRQ - D13

Dual axis Joystick Module - Arduino

From the module, only the left joystick is used, thus only a couple of pins are connected.

  • VCC - 5V
  • A0 (VRx) - A0
  • A1 (VRy) - A1
  • D2 (SW) - D2

Bill of Materials

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

Software Design

External libraries used

  • Adafruit_GFX.h
    • used for TFT display rendering (text, rectangles, fill background, etc)
  • Adafruit_ILI9341.h
    • used for communicating with the TFT display over SPI
  • XPT2046_Touchscreen
    • used for interfacing with the resistive touchscreen overlay
  • EEPROM.h
    • used for accessing non-volatile memory in order to store the best score
  • avr/sleep.h
    • used for delaying rapid changes in order to avoid overriding of actions

Code components

Code splits itself in two main components:

  • interfacing with the hardware, where the first three libraries from above worked as convenient wrappers; that includes:
    • functions that display menus
    • functions that display the grid
    • functions that interpret swipes or button pushes
  • keeping track internally of the current game state; this includes:
    • updating code flags to keep track of game state (identifying current menu)
    • updating inner structures according to performed moves
    • updating inner structure of past moves and best score altogether

Game flow

→ 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.

Implementation details

→ 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.


  • On menu changes, two flags are implied:
    • one that is set the first time the menu needs to be displayed
    • one that is set the whole time the menu is displayed
  • This implements debouncing and also optimizes screen rendering operations.

→ 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.

Optimizations

→ 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.

Used labs

  • Lab0: GPIO
    • for joystick button
  • Lab4: ADC
    • 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 1023
    • XPT2046 touchscreen controller uses a 12-bit ADC to convert measured voltage to a value in range 0 - 4095
  • Lab5: SPI
    • SPI protocol is used to communicate with the display (both for rendering and getting touchscreen input)
  • Lab 1: USART
    • for debbuging code

Results

Conclusions

This project was a good opportunity to see how theoretic notions work in real life, applying them the make something entertaining.

Bibliography & Other materials

pm/prj2025/iivasciuc/marina.oprea2302.txt · Last modified: 2025/05/21 09:09 by marina.oprea2302
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0