Photon Dodge

Published Jun 24, 2026
 1 hours to build
 Beginner

Photon Dodge is a fast-paced reflex game built around a 16×2 LCD display. Unlike traditional LCD games that use only one row, this game transforms both rows into independent racing lanes. A glowing "photon" travels across the screen and the player must press the correct button when it reaches the strike zone.

display image

Components Used

Breadboard
Breadboard
1
ESP32 development board
The main controller of the project. It reads data from the flow sensor and updates the OLED display in real time.
1
16×2 LCD with I2C Module
1
Push buttons
Used to manually start the system.
2
Active buzzer
Alerts when the dustbin reaches its capacity.
1
Jumper Wires
Establishes electrical connections between components.
1
USB Cable
Supplies power and uploads the program to the Arduino.
1
Description

Youtube video demo: Youtube

Step 1: Understanding the Game

The LCD acts like a two-lane race track.

  • Top row = Lane 1
  • Bottom row = Lane 2

A photon appears on one of the lanes and moves from left to right.

Controls

ButtonFunction
Button AHit photon on top row
Button BHit photon on bottom row

Rules

  • Start with 3 lives.
  • Hit the photon when it reaches the last columns.
  • Successful hit = score increases.
  • Miss = lose one life.
  • Speed increases continuously.
  • Game ends when all lives are lost.

Step 2: How It Works

The ESP32:

  1. Generates a random lane.
  2. Creates a photon at column 0.
  3. Moves the photon every few milliseconds.
  4. Checks whether the player pressed the correct button.
  5. Updates score and lives.
  6. Increases speed after successful hits.
  7. Shows Game Over and waits for restart.

Step 3: Circuit Diagram

Connections

Buttons

ButtonESP32 Pin
Top Lane ButtonGPIO13
Bottom Lane ButtonGPIO12

Connect the other side of each button to GND.

Buzzer

BuzzerESP32
+GPIO25
-GND

 

LCD I2C Module

LCDESP32
VCC5V
GNDGND
SDAGPIO21
SCLGPIO22

Step 4: Build the Hardware

  1. Place the ESP32 on the breadboard.
  2. Connect the LCD module.
  3. Add two push buttons.
  4. Connect one side of each button to GND.
  5. Connect the buzzer to GPIO25.
  6. Verify all wiring before powering the circuit.

Step 5: Create Custom Characters

Two custom LCD characters are used:

Photon Character

  *
 ***
*****
*****
 ***
  *

 

Heart Character

Used to display remaining lives.

* *
*****
*****
 ***
  *

 

These characters are stored inside the LCD memory using:

lcd.createChar();

 

Step 6: Initialize the System

During startup:

  • Buttons are configured as INPUT_PULLUP.
  • LCD is initialized.
  • Backlight is enabled.
  • Custom characters are loaded.
  • Random number generator is seeded.
  • First photon is spawned.

 

randomSeed(analogRead(34));
lcd.init();
lcd.backlight();
spawnPhoton();

 

Step 7: Photon Generation

A random lane is selected:

photonRow = random(0,2);

 

Possible values:

  • 0 = Top lane
  • 1 = Bottom lane

The photon starts from:

 

photonCol = 0;

 

Step 8: Photon Movement

The game uses a non-blocking timer based on:

 

millis()

 

Every few milliseconds:

 

photonCol++;

 

The photon moves one column to the right.

This makes animation smooth and responsive.

Step 9: Strike Zone Detection

The last columns of the LCD act as the strike zone:

 

bool inZone = (photonCol >= 13 && photonCol <= 15);

 

When the photon reaches this area, the player must press the correct button.

Step 10: Button Detection

Top button:

pressed(BTN_TOP)

 

Bottom button:

pressed(BTN_BOT)

 

Since INPUT_PULLUP is used:

LOW = Pressed
HIGH = Released

 

Step 11: Successful Hit

If the player presses the correct button inside the strike zone:

 

score++;

 

A short beep is generated:

 

tone(BUZZ,1500,80);

 

The speed becomes faster:

speedDelay = max(150, speedDelay - 12);

 

Then another photon appears.

Step 12: Missing a Photon

If the photon leaves the display:

photonCol > 15

 

The player loses one life:

 

lives--;

 

An error tone is played:

tone(BUZZ,200,250);

 

A new photon is then generated.

Step 13: Game Over Screen

When:

lives == 0

 

The display shows:

GAME OVER
Score: XX

The buzzer plays a low tone and waits for the player to press any button to restart.

Step 14: Main Program Loop

The game continuously repeats:

Step 15: Upload the Code

  1. Open Arduino IDE.
  2. Install the LiquidCrystal_I2C library.
  3. Select your ESP32 board.
  4. Select the COM port.
  5. Upload the sketch.
  6. Press reset.

Your game is ready!

Step 16: Features

  • Uses both LCD rows as independent lanes
  • Random photon spawning
  • Smooth movement using custom characters
  • Dynamic speed increase
  • Score counter
  • Three lives system
  • Sound effects with buzzer
  • Game Over screen
  • Automatic restart
  • Non-blocking code using millis()

Step 17: Future Improvements

  • Double Photon Mode
  • Spawn photons on both rows simultaneously.
  • Combo Multiplier
  • Consecutive hits increase score multiplier.
  • High Score Memory
  • Store highest score using EEPROM.

Power-Ups

  • Slow Motion
  • Extra Life
  • Shield

OLED Version:

  • Upgrade to a 128×64 OLED display.

Joystick Control:

  • Replace buttons with a joystick.

RGB LEDs:

  • Add visual effects for hits and misses.

Conclusion

Photon Dodge transforms a simple 16×2 LCD into a miniature arcade machine. By using both rows as independent lanes, custom characters, sound effects, and adaptive speed control, the game provides surprisingly engaging gameplay while demonstrating important, embedded programming concepts such as state machines, timers, random number generation, and non-blocking animation.

If you enjoyed this project, consider adding EEPROM high-score storage, double-photon mode, or RGB lighting effects to create your own portable LCD arcade console.

Codes

Downloads

PhotonDodge_ino Download
Comments
Ad