Yes—you can build a self-contained dinosaur endless runner with an Arduino, a 128×64 monochrome OLED, and one push button. The Arduino draws a simplified dinosaur, moving cacti, a ground line, and score; pressing the button makes the dinosaur jump, while a collision ends the run.
This is a Dino-inspired recreation, not Google Chrome’s original game. It does not run Chrome or reproduce the browser game’s exact sprites, physics, or scoring.
As an Amazon Associate I earn from qualifying purchases.
What you will build
The finished project is a one-button runner:
- The dinosaur jumps when the button is pressed.
- Cacti move from right to left.
- The score increases as obstacles are passed.
- A cactus collision produces a game-over screen.
- Pressing the button after game over starts a new run.
The graphics use simple rectangles and lines so they fit comfortably in the limited memory and resolution of a small OLED.
Parts and tools
| Part | Specification | Purpose |
|---|---|---|
| Microcontroller | Arduino Uno Rev3 or classic Nano | Runs the game |
| Display | 128×64 monochrome OLED, I2C | Displays graphics and score |
| Input | Momentary push button | Jump and restart control |
| Prototyping | Breadboard and jumper wires | Temporary wiring |
| Optional | Piezo buzzer | Sound effects |
Use one button for the sketch below. Some reference project parts lists show several buttons even though the code uses only one; the extra buttons are unnecessary for this build.
#1 Best Overall
- Powerful ESP-32 Board: Unlock the world of Internet of Things (IoT) and advanced electronics with the heart of this kit: the ESP-32 board. It features a powerful dual-core processor, integrated Wi-Fi and Bluetooth 4.2, making it perfect for building connected, smart devices that communicate with your phone or the cloud. It's fully compatible with the Arduino IDE for easy programming.
- Super Starter Kit: This kit contains over 35 different modules and electronic components, including sensors, displays, motors, and input devices. From LEDs and buttons to an OLED screen, servo motor, and keypad, you have everything needed to explore a vast range of projects in one box.
- Step by Step Online Tutorial: Jump right in with our detailed, beginner-friendly tutorial. Access 30+ projects with complete code, clear circuit diagrams, and step-by-step instructions. Learn the fundamentals of electronics, coding, and how to utilize the ESP-32's unique capabilities without any prior experience.
- Hands-on Learning for All Skill Levels: Perfect for students, makers, engineers, and hobbyists. Start with basic circuits and coding, then progress to intermediate and advanced IoT applications. Build practical projects like weather stations, smart home controllers, remote-controlled devices, and interactive gadgets. The skills you learn are the foundation for real-world innovation.
- Quality & Great Support: Elegoo is committed to quality. We provide a clear, detailed tutorial guide, refined code, and a well-organized component kit. All modules are carefully selected for reliability and ease of use. Our dedicated technical support team and active online community are ready to help you succeed in your learning journey.
Check the OLED before wiring
Do not assume every small OLED is identical. Confirm these details from the rear silkscreen, product listing, or datasheet:
- Resolution: 128×64 rather than 128×32.
- Interface: I2C rather than SPI.
- Controller: SSD1306, SH1106, or another compatible controller.
- Supply requirements: some breakouts accept 5V, while bare 3.3V modules do not.
- I2C address: commonly
0x3C, but sometimes0x3D.
The Adafruit SSD1306 library is a good fit for a genuine SSD1306 breakout. An SH1106 module may display shifted or incorrect graphics with an SSD1306 configuration; use a controller-appropriate library such as U8g2 when necessary.
Wire the OLED to an Arduino Uno
| OLED pin | Arduino Uno |
|---|---|
| VCC or VIN | 5V only if the breakout explicitly supports 5V input |
| GND | GND |
| SDA or DATA | A4 |
| SCL or CLK | A5 |
| RST | Leave disconnected when the sketch uses OLED_RESET -1 |
On the Uno, A4 is the hardware I2C SDA pin and A5 is SCL. Do not move I2C wiring to arbitrary digital pins. See Adafruit’s OLED wiring guide for breakout-specific reset and power details.
Wire the active-low button
Button terminal 1 → Arduino D3
Button terminal 2 → Arduino GND
The sketch enables the Uno’s internal pull-up resistor:
pinMode(BUTTON_PIN, INPUT_PULLUP);
| Button condition | D3 reading |
|---|---|
| Released | HIGH |
| Pressed | LOW |
This is an active-low arrangement. Do not wire this button to 5V for the code below.
Install the Arduino libraries
- Open Arduino IDE.
- Select Tools → Manage Libraries.
- Search for Adafruit SSD1306 and install it.
- Search for Adafruit GFX Library and install it.
- Open an SSD1306 I2C example and upload it before debugging the game.
Adafruit GFX supplies drawing primitives such as pixels, lines, rectangles, and text, while Adafruit SSD1306 manages the display buffer and controller. The official installation guidance is in Adafruit’s library guide.
Rank #2
- 30+ Guided Electronics Projects: Start with LEDs and build toward LCD1602 displays, RFID access, motion detection, distance sensing, motor control and environmental monitoring for STEM learning, coding clubs, classrooms and hobby projects
- 200+ Components Across 63 Types: Includes an ELEGOO UNO R3 controller, LCD1602, RC522 RFID, RTC, HC-SR501 PIR sensor, ultrasonic sensor, DHT11, GY-521, MAX7219, keypad, joystick, relay, SG90 servo, stepper motor, breadboard and more
- Begin Without Soldering: Pre-soldered modules, a solderless breadboard, organized storage case and small-parts box reduce setup time and help beginners move from lesson to lesson while keeping LEDs, ICs, wires and sensors easy to find
- Learn, Modify and Create: Program the ELEGOO UNO R3 board with Arduino IDE using the included PDF tutorial and example code, then adjust sensor thresholds, timing, display text and motor behavior to turn guided lessons into original projects
- Flexible Power and Project Setup: Includes a 9 V, 1 A power supply, breadboard power module, 9 V battery and USB cable to support controller, breadboard and module experiments without sourcing basic setup accessories separately
Run an OLED test first
Open an example from File → Examples → Adafruit SSD1306, choose the I2C example matching your display geometry, and upload it. Confirm that the OLED renders text or graphics correctly. If the example does not work, the game sketch will not work either.
Recommended Free Tools
If your scanner finds 0x3D instead of 0x3C, change SCREEN_ADDRESS in the game sketch. Also verify that the example is configured for 128×64, not 128×32.
Complete Arduino sketch
This version improves on a basic implementation with explicit game states, button edge detection, debounce timing, bounded speed, obstacle spacing, and rectangle-based collision detection.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
const uint8_t BUTTON_PIN = 3;
const uint16_t FRAME_INTERVAL = 50; // nominally 20 updates per second
const int16_t GROUND_Y = 49;
const int16_t DINO_X = 14;
const int16_t DINO_WIDTH = 12;
const int16_t DINO_HEIGHT = 14;
const int16_t DINO_GROUND_Y = GROUND_Y - DINO_HEIGHT;
const int16_t JUMP_IMPULSE = -13;
const int16_t GRAVITY = 2;
const int16_t CACTUS_Y = GROUND_Y - 14;
const int16_t CACTUS_WIDTH = 8;
const int16_t CACTUS_HEIGHT = 14;
const int16_t MIN_OBSTACLE_GAP = 42;
const int16_t MAX_GAME_SPEED = 6;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
enum GameState { TITLE, PLAYING, GAME_OVER };
GameState gameState = TITLE;
int16_t dinoY = DINO_GROUND_Y;
int16_t velocityY = 0;
bool airborne = false;
int16_t cactusX = SCREEN_WIDTH + 10;
int16_t nextCactusX = SCREEN_WIDTH + 10 + MIN_OBSTACLE_GAP;
uint16_t score = 0;
uint16_t highScore = 0;
int16_t gameSpeed = 3;
bool lastButtonState = HIGH;
unsigned long lastButtonChange = 0;
unsigned long lastFrame = 0;
unsigned long lastDifficultyIncrease = 0;
unsigned long lastScoreTime = 0;
bool overlaps(int16_t ax, int16_t ay, int16_t aw, int16_t ah,
int16_t bx, int16_t by, int16_t bw, int16_t bh) {
return ax < bx + bw &&
ax + aw > bx &&
ay < by + bh &&
ay + ah > by;
}
bool justPressed() {
bool reading = digitalRead(BUTTON_PIN);
unsigned long now = millis();
if (reading != lastButtonState && now - lastButtonChange > 25) {
lastButtonChange = now;
lastButtonState = reading;
return reading == LOW;
}
return false;
}
void waitForRelease() {
lastButtonState = digitalRead(BUTTON_PIN);
lastButtonChange = millis();
}
void resetRun() {
dinoY = DINO_GROUND_Y;
velocityY = 0;
airborne = false;
cactusX = SCREEN_WIDTH + 12;
nextCactusX = cactusX + MIN_OBSTACLE_GAP + random(0, 35);
score = 0;
gameSpeed = 3;
lastDifficultyIncrease = millis();
lastScoreTime = millis();
waitForRelease();
}
void drawDino() {
// Body and head
display.fillRect(DINO_X + 3, dinoY + 4, 8, 8, SSD1306_WHITE);
display.fillRect(DINO_X + 7, dinoY, 6, 7, SSD1306_WHITE);
// Eye and legs
display.drawPixel(DINO_X + 10, dinoY + 2, SSD1306_BLACK);
display.drawLine(DINO_X + 4, dinoY + 12, DINO_X + 4, dinoY + 14, SSD1306_WHITE);
display.drawLine(DINO_X + 9, dinoY + 12, DINO_X + 9, dinoY + 14, SSD1306_WHITE);
}
void drawCactus(int16_t x) {
display.fillRect(x, CACTUS_Y, CACTUS_WIDTH, CACTUS_HEIGHT, SSD1306_WHITE);
display.fillRect(x - 3, CACTUS_Y + 5, 3, 4, SSD1306_WHITE);
display.fillRect(x + CACTUS_WIDTH, CACTUS_Y + 3, 3, 4, SSD1306_WHITE);
}
void drawScore() {
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(88, 2);
display.print(F("S:"));
display.print(score);
}
void renderGame() {
display.clearDisplay();
display.drawLine(0, GROUND_Y, SCREEN_WIDTH - 1, GROUND_Y, SSD1306_WHITE);
drawScore();
drawDino();
drawCactus(cactusX);
drawCactus(nextCactusX);
display.display();
}
void renderTitle() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(18, 10);
display.print(F("DINO"));
display.setTextSize(1);
display.setCursor(27, 38);
display.print(F("Press to start"));
display.display();
}
void renderGameOver() {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(16, 8);
display.print(F("GAME"));
display.setCursor(16, 27);
display.print(F("OVER"));
display.setTextSize(1);
display.setCursor(16, 51);
display.print(F("Score: "));
display.print(score);
display.setCursor(78, 51);
display.print(F("Press"));
display.display();
}
void startRun() {
resetRun();
gameState = PLAYING;
}
void updateGame() {
unsigned long now = millis();
if (justPressed() && !airborne) {
velocityY = JUMP_IMPULSE;
airborne = true;
}
dinoY += velocityY;
velocityY += GRAVITY;
if (dinoY >= DINO_GROUND_Y) {
dinoY = DINO_GROUND_Y;
velocityY = 0;
airborne = false;
}
cactusX -= gameSpeed;
nextCactusX -= gameSpeed;
if (cactusX + CACTUS_WIDTH < 0) {
cactusX = nextCactusX + MIN_OBSTACLE_GAP + random(0, 35);
}
if (nextCactusX + CACTUS_WIDTH < 0) {
nextCactusX = cactusX + MIN_OBSTACLE_GAP + random(0, 35);
}
if (now - lastScoreTime >= 250) {
score++;
lastScoreTime = now;
}
if (now - lastDifficultyIncrease >= 3000) {
if (gameSpeed < MAX_GAME_SPEED) {
gameSpeed++;
}
lastDifficultyIncrease = now;
}
bool hitCactus = overlaps(
DINO_X + 2, dinoY + 2, DINO_WIDTH - 3, DINO_HEIGHT - 2,
cactusX, CACTUS_Y, CACTUS_WIDTH, CACTUS_HEIGHT) ||
overlaps(
DINO_X + 2, dinoY + 2, DINO_WIDTH - 3, DINO_HEIGHT - 2,
nextCactusX, CACTUS_Y, CACTUS_WIDTH, CACTUS_HEIGHT);
if (hitCactus) {
if (score > highScore) highScore = score;
gameState = GAME_OVER;
waitForRelease();
}
}
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
randomSeed(analogRead(A0));
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
while (true) {
// Stop here if the OLED cannot be initialized.
}
}
display.clearDisplay();
display.display();
renderTitle();
}
void loop() {
unsigned long now = millis();
if (gameState == TITLE) {
if (justPressed()) startRun();
return;
}
if (gameState == GAME_OVER) {
if (justPressed()) {
startRun();
}
return;
}
if (now - lastFrame < FRAME_INTERVAL) return;
lastFrame = now;
updateGame();
if (gameState == PLAYING) renderGame();
else renderGameOver();
}
Before uploading, check SCREEN_ADDRESS, display dimensions, and controller type. If your OLED is not an SSD1306, this exact display object may not be appropriate.
How the sketch works
Display initialization
The constructor creates a 128×64 framebuffer and uses the Arduino Uno’s I2C bus. OLED_RESET -1 tells the library that the display reset pin is not separately connected. Initialization stops in an infinite loop if the display cannot be detected.
Free tools Windows power users keep installed
One-click scans. No signup required.
Button input
The button is read as active-low. justPressed() detects a transition from released to pressed and ignores rapid changes for 25 milliseconds. This prevents one long press from producing repeated jumps.
Rank #3
- 35+ Guided Electronics Projects: Progress from LEDs and buttons to RFID access, real-time clocks, motion and distance sensing, environmental monitoring, motor control and interactive displays for STEM learning, coding clubs and maker projects
- More I/O and Memory for Larger Builds: The MEGA 2560 R3 provides 54 digital I/O pins, including 15 PWM outputs, 16 analog inputs, 4 hardware serial ports and 256 KB flash for projects that combine more sensors, controls and displays
- 200+ Components for Prototyping: Includes LCD1602, RC522 RFID, RTC, DHT11, HC-SR501 PIR, ultrasonic and water-level sensors, GY-521, MAX7219, keypad, joystick, rotary encoder, relay, SG90 servo, stepper motor, DC motor, breadboard and more
- Learn, Modify and Create: Follow 35+ guided lessons with example code, then adjust sensor thresholds, timing, display text, motor behavior and control logic to turn structured exercises into access systems, monitors, alarms and interactive projects
- Organized for Repeatable Learning: Pre-soldered modules, a solderless breadboard, storage case and small-parts box reduce setup time and keep sensors, LEDs, ICs, wires and other components easy to find between projects
Jump physics
OLED coordinates increase downward. Therefore the negative jump impulse moves the dinosaur upward. Gravity increases the vertical velocity until it becomes positive and pulls the dinosaur back down. The landing code uses >=, rather than exact equality, so the dinosaur cannot fall through the ground when its velocity skips over the precise coordinate.
Obstacles
Two cactus positions move left by gameSpeed each update. When one leaves the screen, it is placed beyond the other cactus with a minimum gap and a random additional separation. The speed increases every three seconds until it reaches MAX_GAME_SPEED.
Collision detection
The overlaps() function performs axis-aligned bounding-box collision. It checks horizontal and vertical overlap, so collisions are detected while the dinosaur is rising, falling, or standing.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11The dinosaur’s collision rectangle is slightly smaller than its visible drawing. This makes contact feel less unfair at the edges. Visual pixels and gameplay hitboxes do not have to be identical.
Timing and rendering
The loop uses millis() rather than long blocking delays. The nominal 50-millisecond interval corresponds to about 20 updates per second, although actual performance depends on the board, library, and display transfer. Each frame is drawn into the buffer and sent with one display.display() call.
Scoring
This sketch increases the score approximately every 250 milliseconds. It is a custom score and is not compatible with Chrome’s scoring system. A production version could award points only when an obstacle passes the dinosaur, or save a high score to EEPROM once at game over rather than writing repeatedly during play.
Rank #4
- TURN CODE INTO REAL-WORLD RESULTS — Follow 22+ guided lessons to make LEDs blink, read temperature and distance, move servo and stepper motors, control an LCD and respond to joystick or IR input; ideal for a family weekend build, homeschool unit, coding club or STEM classroom
- MORE PROJECT VARIETY IN ONE ORGANIZED KIT — Includes the UNO R3 controller, LCD1602 with pre-soldered header, breadboard power module, ultrasonic and DHT11 sensors, joystick, IR receiver and remote, SG90 servo, stepper motor, relay, DC motor, fan blade, displays, LEDs, buttons, resistors and jumper wires
- START WITHOUT SOLDERING — Plug-in modules, a solderless breadboard and the pre-soldered LCD help beginners focus on wiring, code and testing; the illustrated component list makes it easier to find each part and move from one lesson to the next
- LEARN THE LOGIC, THEN CREATE YOUR OWN — Use Arduino IDE and the included example code to understand digital input and output, analog sensing, timing, motor control and display functions, then change thresholds, speeds and sequences for alarms, environmental monitors, reaction games and motion projects
- CLEAR SETUP SUPPORT FOR FIRST-TIME BUILDERS — Download the latest tutorial and code, select the UNO board and correct computer port, check component polarity and breadboard rows, and keep power-module input at 9V or below; younger learners should work with an experienced adult
Troubleshooting
The OLED is completely blank
- Check VCC and GND.
- Confirm SDA is on Uno A4 and SCL is on A5.
- Run an I2C scanner.
- Try
0x3Cand0x3Daccording to the scanner result. - Confirm the sketch uses
128, 64. - Run the library’s example sketch.
- Check whether the module is SPI rather than I2C.
- Verify that the controller is SSD1306.
If the module is SH1106, use a matching U8g2 configuration or another library supporting that controller. Arduino also documents ss_oled, which is designed for constrained devices and supports several controller and address combinations.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →The display image is shifted or corrupted
This commonly indicates a controller or geometry mismatch. Recheck whether the module is SH1106, whether it is 128×32 rather than 128×64, and whether the selected library constructor matches the hardware.
The button does nothing
- Connect one button terminal to D3 and the other to GND.
- Use
INPUT_PULLUP. - Treat LOW as pressed.
- Make sure the button is not rotated across the wrong breadboard rows.
- Test D3 with a small sketch that prints
digitalRead(3)to Serial Monitor.
The dinosaur jumps repeatedly
The code must respond to a press edge, not continuously to the LOW level. Confirm that justPressed() and its debounce interval are present. Also make sure the button is released before restarting.
The dinosaur passes through a cactus
Use rectangle-overlap collision rather than checking only whether the dinosaur is exactly on the ground. Exact coordinate equality misses collisions during ascent and descent.
The game becomes unfairly fast
Reduce MAX_GAME_SPEED, increase MIN_OBSTACLE_GAP, or lengthen the difficulty interval. At very high speeds an obstacle can move a large distance between updates, making the game feel unfair and increasing the risk of tunneling through the player.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Uploading fails
Check the board, processor, port, and USB cable. Classic Nano clones may require a different processor or bootloader choice under Tools → Processor. Close Serial Monitor before uploading. Diagnose compilation and upload errors separately from OLED wiring.
Best Value
- Perfect choice for beginners to learn, electronics and program.
- This kit with tutorial user manual containing more than 20 lessons,code,Libraries, datasheets, and so on.
- 100% Compatible with program.
- Inlcude type motors and LCDs with servo motor, stepper motor and DC Motor; LCD 1602, LCD 4-bit 7-segment Display etc.
- LCD 1602 module with pin header (not need to be soldered by yourself)
Uno versus Nano
The Uno is easier to wire on a breadboard and has clearly labeled, full-size headers. A Nano is better for a compact enclosure and has similar constraints when it is a classic ATmega328P-based board. Nano clones can require different upload settings, so select the exact board and processor variant in the IDE.
Choosing an OLED library
| Library | Best fit | Trade-off |
|---|---|---|
| Adafruit SSD1306 + GFX | Documented SSD1306 displays and beginner projects | Requires matching controller and geometry |
| U8g2 | SH1106 and broad controller support | Different API and more configuration choices |
| ss_oled | Constrained boards and several controller/address combinations | Different API from Adafruit libraries |
Keep the Adafruit libraries when your module is a correctly identified SSD1306. Switch libraries when the hardware—not the game logic—is the problem.
Useful extensions
- Replace rectangles with bitmap dinosaur and cactus sprites stored in program memory.
- Add two-frame running animation.
- Add a second button for ducking or dedicated restart.
- Add flying obstacles and a duck mechanic.
- Use a piezo buzzer for jumping, scoring, and game-over sounds.
- Add a title screen and persistent high score.
- Write EEPROM only when a new high score is finalized to avoid unnecessary wear.
- Use a faster board such as an ESP32 for larger graphics or more elaborate audio.
- Track obstacle positions with a struct if you add several cactus types.
Can a 128×32 OLED be used?
Yes, but not with the unmodified layout. You must move the ground, reduce sprite heights, and redesign score and title-screen placement. A 128×64 display is the practical baseline for this sketch.
Sources and further documentation
- Arduino Project Hub Dino implementation
- Arduino Uno Rev3 documentation
- Adafruit 128×64 OLED wiring
- Adafruit 128×32 OLED wiring
- Adafruit SSD1306 and GFX installation
- Arduino U8g2 library documentation
- Arduino ss_oled library documentation
Frequently Asked Questions
Can the Arduino run the real Chrome Dino Game?
No. This project recreates the endless-runner concept locally with Arduino code and simple OLED graphics; it does not run Chrome or the browser game’s original code.
Why is the OLED address usually 0x3C?
0x3C is common for small I2C OLED modules, but 0x3D is also used. An I2C scanner is the reliable way to identify the address on your hardware.
Can I add a second button?
Yes. Add another input with its own pull-up configuration, then assign it to restart, ducking, pause, or menu navigation.
Can I save the high score?
Yes. Store it in EEPROM only when a run ends with a new high score, not every frame, to avoid unnecessary memory wear.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesCan I add sound?
Yes. A piezo buzzer can be connected to another digital pin and triggered during jump, scoring, or game-over events without changing the OLED wiring.
The Bottom Line
A Uno or Nano, a correctly identified 128×64 I2C OLED, and one active-low button are enough to build a playable Dino-inspired runner. The key reliability fixes are verifying the OLED controller and address, using non-blocking timing, detecting button edges, bounding game speed, and checking full rectangle overlap for collisions.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




