Who says you need a high-resolution monitor and a powerful processor to play a video game? This code transforms a standard Arduino Nano, an analog joystick, and a basic 16x2 text display into a fully playable, fast-paced arcade game. You control a cursor, dodging incoming blocks while trying to survive and rack up a high score. Code for this project is available here.
The Hardware Setup
- The Controller: A standard analog joystick module. The vertical axis is wired to analog pin A0 for moving the player, the horizontal axis is on A1 for pausing the game, and the physical click button is on digital pin 2 for restarting after a game over.
- The Screen: A basic 16x2 I2C LCD (operating at address 0x27) acting as the game engine's display monitor.
Component Pinout Guide
Wire your components to the Arduino Nano using the following connections (note that A4 and A5 are the standard I2C pins for the Nano):
| Component | Component Pin | Arduino Nano Pin | Function |
|---|---|---|---|
| Analog Joystick | VCC | 5V | Power supply |
| Analog Joystick | GND | GND | Ground |
| Analog Joystick | VRy / Y-Axis | A0 | Vertical movement (Up/Down) |
| Analog Joystick | VRx / X-Axis | A1 | Horizontal movement (Pause) |
| Analog Joystick | SW / Switch | D2 | Push button (Restart) |
| I2C LCD | VCC | 5V | Power supply |
| I2C LCD | GND | GND | Ground |
| I2C LCD | SDA | A4 | I2C Data line |
| I2C LCD | SCL | A5 | I2C Clock line |
How It Works: Gameplay Mechanics
You play as an arrow cursor (>) locked to the left side of the screen, restricted to moving between the top row and the bottom row. Every few seconds, solid square obstacles (0xFF) spawn on the far right edge of the display.
Every second, these obstacles shift one column to the left. You must use the joystick to switch rows and avoid them. If an obstacle hits your column while you are in the same row, it is Game Over. If it passes you safely and exits the screen, your score increases by one.
Technical Highlights in the Code
obstacleX
and obstacleRow. This acts as an object pool, effectively keeping track
of the specific coordinates of every active block without overflowing the Arduino's limited
memory.delay() function, or player inputs would be entirely
ignored while the game pauses. This code uses millis() to create
separate, independent engine timers: one interval for spawning new blocks (4000ms) and another for
shifting them left (1000ms). The player can move their joystick instantly at any time between
these frame updates.