Arduino Virtual Pet Game
on OLED Display
Build a Tamagotchi-style digital pet using Arduino Uno + SSD1306 OLED in the free Wokwi simulator — no hardware needed!
Overview
What You'll Build
A fully interactive digital pet that lives on a tiny OLED screen — feed it, play with it, let it sleep!
Components
What You Need
All parts are available virtually inside Wokwi — nothing to buy!
Wiring
Pin Connections
Connect the OLED via I2C, buttons to digital pins, and the buzzer to Pin 8.
Full Connection Table
| From | To (Arduino) | Wire Color |
|---|---|---|
| OLED GND | GND | ⬛ Black |
| OLED VCC | 5V | 🔴 Red |
| OLED SDA | A4 | 🔵 Blue |
| OLED SCL | A5 | 🟢 Green |
| Button 1 (Feed) Pin 1 | Pin 2 | 🟢 Green |
| Button 1 (Feed) Pin 2 | GND | ⬛ Black |
| Button 2 (Play) Pin 1 | Pin 3 | 🔵 Blue |
| Button 2 (Play) Pin 2 | GND | ⬛ Black |
| Button 3 (Sleep) Pin 1 | Pin 4 | 🟡 Yellow |
| Button 3 (Sleep) Pin 2 | GND | ⬛ Black |
| Buzzer (+) | Pin 8 | 🔴 Red |
| Buzzer (–) | GND | ⬛ Black |
Instructions
Step-by-Step Guide
Follow these steps to get your virtual pet running in minutes.
-
Open Wokwi in your browser
Go to wokwi.com and click "New Project" → Arduino Uno. No account needed to try it!
-
Add components to the diagram
Click the blue + button to add: SSD1306 OLED, three Push Buttons, and one Buzzer. Alternatively, paste the diagram.json below directly — it auto-places everything.
-
Paste the diagram.json
Click the diagram.json tab in Wokwi and replace its content with the JSON code from the Diagram JSON section below. This sets up all wiring automatically.
-
Add the Arduino libraries
In Wokwi, click Libraries (book icon) and search for
Adafruit GFXandAdafruit SSD1306. Add both.In Wokwi these libraries are pre-installed — just make sure the#includelines are at the top of your sketch. -
Paste the Arduino code
Open the sketch.ino tab and paste the full code from the Code section below. Replace any existing code completely.
-
Click the green Play ▶ button
Hit the green ▶ Start Simulation button. You'll see the OLED light up with "Virtual Pet!" and hear the startup melody. Your pet is alive!
Expected output: OLED shows the welcome screen for 2 seconds, then the pet face with bouncing animation and live status bars. -
Interact with the buttons
Click the green button to feed, blue to play, yellow to sleep. Watch the pet's face and status bars react in real time. If you ignore it too long — it will die! 💀
-
Open the Serial Monitor (optional)
Click the Serial Monitor tab in Wokwi to see live stat values printed every 5 seconds: Hunger, Happiness, and Energy numbers.
Source Code
Arduino Sketch
Copy and paste this entire code into your Wokwi sketch.ino file.
#include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Button pins const int BTN_FEED = 2; const int BTN_PLAY = 3; const int BTN_SLEEP = 4; // Buzzer pin const int BUZZER = 8; // Pet stats (0–100) int hunger = 50; // higher = more hungry int happiness = 70; int energy = 80; int age = 0; // Animation int frame = 0; unsigned long lastUpdate = 0; unsigned long lastAnim = 0; // ─────────────── SETUP ─────────────── void setup() { Serial.begin(9600); pinMode(BTN_FEED, INPUT_PULLUP); pinMode(BTN_PLAY, INPUT_PULLUP); pinMode(BTN_SLEEP, INPUT_PULLUP); pinMode(BUZZER, OUTPUT); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("Display failed!"); for (;;); } display.clearDisplay(); display.setTextColor(SSD1306_WHITE); // Welcome screen playStartupSound(); display.setTextSize(2); display.setCursor(10, 20); display.println("Virtual"); display.setCursor(25, 40); display.println("Pet!"); display.display(); delay(2000); } // ─────────────── LOOP ──────────────── void loop() { unsigned long now = millis(); // Decay stats every 5 seconds if (now - lastUpdate > 5000) { hunger = min(100, hunger + 3); happiness = max(0, happiness - 2); energy = max(0, energy - 2); age++; lastUpdate = now; if (hunger > 80 || happiness < 20 || energy < 20) playWarningSound(); Serial.print("Hunger:"); Serial.print(hunger); Serial.print(" Happy:"); Serial.print(happiness); Serial.print(" Energy:"); Serial.println(energy); } // Bounce animation frame if (now - lastAnim > 500) { frame = (frame + 1) % 2; lastAnim = now; } // ── Button checks ── if (digitalRead(BTN_FEED) == LOW) { hunger = max(0, hunger - 30); happiness = min(100, happiness + 5); playEatSound(); showMessage("Fed!"); delay(500); } if (digitalRead(BTN_PLAY) == LOW) { if (energy > 20) { happiness = min(100, happiness + 20); energy = max(0, energy - 15); playHappySound(); showMessage("Fun!"); } else { playSadSound(); showMessage("Too tired!"); } delay(500); } if (digitalRead(BTN_SLEEP) == LOW) { energy = min(100, energy + 40); playSleepSound(); showMessage("Zzz..."); delay(1000); } // ── Draw ── display.clearDisplay(); if (hunger >= 100 || happiness <= 0) { playDeathSound(); drawDead(); } else { drawPet(); drawStats(); drawButtons(); } display.display(); delay(100); } // ════════════ SOUND FUNCTIONS ════════════ void playStartupSound() { tone(BUZZER, 523, 150); delay(150); // C tone(BUZZER, 659, 150); delay(150); // E tone(BUZZER, 784, 200); delay(200); // G } void playEatSound() { tone(BUZZER, 400, 100); delay(120); tone(BUZZER, 500, 100); delay(120); tone(BUZZER, 600, 100); delay(120); } void playHappySound() { tone(BUZZER, 800, 100); delay(120); tone(BUZZER, 1000, 100); delay(120); tone(BUZZER, 1200, 150); delay(170); } void playSleepSound() { tone(BUZZER, 700, 200); delay(220); tone(BUZZER, 600, 200); delay(220); tone(BUZZER, 500, 300); delay(320); } void playSadSound() { tone(BUZZER, 400, 200); delay(220); tone(BUZZER, 300, 300); delay(320); } void playWarningSound() { tone(BUZZER, 800, 100); delay(150); tone(BUZZER, 800, 100); delay(150); } void playDeathSound() { static bool played = false; if (!played) { tone(BUZZER, 500, 300); delay(320); tone(BUZZER, 400, 300); delay(320); tone(BUZZER, 300, 500); delay(520); played = true; } } // ════════════ DRAWING FUNCTIONS ════════════ void drawPet() { int x = 64, y = 30; display.fillCircle(x, y, 12, SSD1306_WHITE); // Body if (hunger > 70) { // Hungry display.fillCircle(x-4, y-2, 2, SSD1306_BLACK); display.fillCircle(x+4, y-2, 2, SSD1306_BLACK); display.fillCircle(x, y+4, 3, SSD1306_BLACK); } else if (energy < 30) { // Tired display.drawLine(x-5,y-2, x-2,y-2, SSD1306_BLACK); display.drawLine(x+2,y-2, x+5,y-2, SSD1306_BLACK); if (frame == 0) { display.setCursor(x+12,y-8); display.print("Z"); } } else if (happiness < 40) { // Sad display.fillCircle(x-4,y-2,2,SSD1306_BLACK); display.fillCircle(x+4,y-2,2,SSD1306_BLACK); display.drawLine(x-3,y+6, x, y+4, SSD1306_BLACK); display.drawLine(x, y+4, x+3,y+6, SSD1306_BLACK); } else { // Happy display.fillCircle(x-4,y-2,2,SSD1306_BLACK); display.fillCircle(x+4,y-2,2,SSD1306_BLACK); display.drawLine(x-5,y+3, x-2,y+5, SSD1306_BLACK); display.drawLine(x-2,y+5, x+2,y+5, SSD1306_BLACK); display.drawLine(x+2,y+5, x+5,y+3, SSD1306_BLACK); if (frame == 0) y -= 2; // Bounce } display.fillCircle(x-8, y+13, 3, SSD1306_WHITE); // Feet display.fillCircle(x+8, y+13, 3, SSD1306_WHITE); } void drawStats() { display.setTextSize(1); // Hunger bar (inverted) display.setCursor(0,0); display.print("H:"); int h = map(100-hunger, 0,100, 0,20); display.drawRect(12,0,22,6,SSD1306_WHITE); display.fillRect(13,1,h,4,SSD1306_WHITE); // Happiness bar display.setCursor(38,0); display.print("E:"); int e = map(happiness, 0,100, 0,20); display.drawRect(50,0,22,6,SSD1306_WHITE); display.fillRect(51,1,e,4,SSD1306_WHITE); // Energy bar display.setCursor(76,0); display.print("T:"); int t = map(energy, 0,100, 0,20); display.drawRect(88,0,22,6,SSD1306_WHITE); display.fillRect(89,1,t,4,SSD1306_WHITE); // Age display.setCursor(114,0); display.print(age); } void drawButtons() { display.setTextSize(1); display.setCursor(0, 56); display.print("Feed"); display.setCursor(44, 56); display.print("Play"); display.setCursor(88, 56); display.print("Sleep"); } void drawDead() { display.setTextSize(2); display.setCursor(20,15); display.println("R.I.P."); display.setTextSize(1); display.setCursor(10,35); display.println("Pet has died"); display.setCursor(5,50); display.println("Reset to restart"); } void showMessage(const char* msg) { display.clearDisplay(); display.setTextSize(2); display.setCursor(20,25); display.println(msg); display.display(); }
Diagram JSON
Wokwi diagram.json
Paste this into the diagram.json tab in Wokwi to auto-wire all components.
{
"version": 1,
"author": "Wokwi",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} },
{ "type": "wokwi-ssd1306", "id": "oled", "top": -100, "left": 100, "attrs": {} },
{ "type": "wokwi-pushbutton", "id": "btn1", "top": 150, "left": -50, "attrs": { "color": "green" } },
{ "type": "wokwi-pushbutton", "id": "btn2", "top": 150, "left": 20, "attrs": { "color": "blue" } },
{ "type": "wokwi-pushbutton", "id": "btn3", "top": 150, "left": 90, "attrs": { "color": "yellow" } },
{ "type": "wokwi-buzzer", "id": "buz", "top": 100, "left": -100, "attrs": {} }
],
"connections": [
[ "oled:GND", "uno:GND.1", "black", ["v0"] ],
[ "oled:VCC", "uno:5V", "red", ["v0"] ],
[ "oled:SDA", "uno:A4", "blue", ["v0"] ],
[ "oled:SCL", "uno:A5", "green", ["v0"] ],
[ "btn1:1.l", "uno:2", "green", ["v0"] ],
[ "btn1:2.l", "uno:GND.2", "black", ["v0"] ],
[ "btn2:1.l", "uno:3", "blue", ["v0"] ],
[ "btn2:2.l", "uno:GND.2", "black", ["v0"] ],
[ "btn3:1.l", "uno:4", "yellow", ["v0"] ],
[ "btn3:2.l", "uno:GND.2", "black", ["v0"] ],
[ "buz:1", "uno:8", "red", ["v0"] ],
[ "buz:2", "uno:GND.3", "black", ["v0"] ]
]
}
Explanation
How It Works
The pet has 4 live stats that change every 5 seconds — and you must keep them healthy!
Reduces hunger, slightly boosts happiness. Use this when hunger bar is getting full.
Boosts happiness significantly but drains energy. Won't work if energy ≤ 20.
Restores energy quickly. Use when the pet is tired — you'll see "Z" floating above it.
Audio
Sound Effects
The buzzer on Pin 8 plays different tone sequences for each event.
Education
What You'll Learn
This project teaches core embedded systems concepts in a fun, hands-on way.
Comments
Post a Comment