Community project
Led Matrix Games-UnoR3
This project builds a retro arcade gaming console on an Arduino Uno, featuring five playable games displayed on an 8x8 LED matrix. Players control games with a dual-axis joystick and push buttons, with audio feedback from a buzzer and visual status indicators from RGB LEDs. The guide includes a complete wiring diagram, parts list, and step-by-step assembly instructions to get the hardware connected and ready for programming.
The firmware supports Snake, Spammer, Space Invaders, Pong, and Dino Runner modes, each with independent high-score tracking stored in the Arduino's EEPROM. The MAX7219 driver chip handles all LED matrix control, simplifying the display logic and freeing up processor resources for smooth gameplay. Builders will have a fully functional arcade cabinet they can expand with additional games or customize with their own gameplay mechanics.
Wiring diagram

Gather all the parts
Assemble it in 7 steps
1. Place the Arduino and make power rails
Put the Arduino Uno beside the breadboard. Run a red jumper from Uno 5V to the breadboard positive rail and a black jumper from Uno GND to the negative rail, so every module shares the same power and ground.
- If a long breadboard rail has a break in its middle, join the two halves with short jumper wires.
- Do not join the 5V rail to the GND rail; that can damage the Arduino or its USB connection.
2. Connect the LED matrix
Use the input connector on the MAX7219 matrix. Connect VCC to 5V (power), GND to GND (ground), DIN to Uno D12 (display data), CLK to Uno D11 (display clock), and CS or LOAD to Uno D10 (display select). Leave DOUT empty because this project has only one matrix.
- Look for DIN, not DOUT. DOUT is only for a second LED-matrix module.
- Make sure VCC and GND are not swapped — swapped power can damage the display module.
3. Connect the joystick
Connect the joystick module VCC to 5V (power), GND to GND (ground), VRx to A1 (left/right control), and VRy to A0 (up/down control). Leave the joystick SW pin unconnected because the separate game button is used instead.
- The stick should return to its middle position when you release it.
- Do not connect VRx or VRy to 5V; they must go to A1 and A0 for the Arduino to read the stick position.
4. Add the two push buttons
Place each small four-leg push button across the breadboard center gap. For the main game button, connect one switched side to D2 (game action) and the opposite switched side to GND (ground). For the sound button, connect one switched side to D3 (sound on/off) and the opposite switched side to GND (ground).
- On each tactile button, the two legs on one side are already connected together. Use one leg from each opposite side.
- Do not connect either button to 5V; the code safely uses the Arduino's built-in pull-up connection to GND.
5. Connect your three-pin buzzer module
On your buzzer module, connect S to Uno D4 (sound-control signal), + to Uno 5V (power), and – to Uno GND (ground).
- The labels may be printed as S, +, and – on the circuit board. Match them exactly.
- This three-pin module is usually an active buzzer: it may make only one fixed-pitch sound instead of all the different game notes. Make sure + and – are not swapped — reversed power can damage the module.
6. Wire the green and red status lights
For the green light, connect Uno D5 to one end of the green 220 Ω resistor (signal), connect the other resistor end to the green LED's long leg (current-limited power), and connect the LED's short leg to GND (ground). Repeat with Uno D6, the red 220 Ω resistor, and the red LED.
- The LED long leg is positive. The short leg and the flat side of the LED body mark its negative side.
- Keep one resistor in series with each LED — without it, too much current can damage the LED or the Arduino pin.
7. Check everything before USB power
Check that all GND wires reach the same Uno GND rail, the LED matrix is connected to DIN rather than DOUT, the buzzer uses S to D4, + to 5V, and – to GND, and both LEDs have resistors. Then plug the Uno into USB for power.
- When it starts, move the joystick up or down to choose a game, press the main button to start, and press the sound button while at a game icon to turn sound on or off.
- Unplug USB before moving any wires; this reduces the chance of accidentally shorting 5V to GND.
Review all connections
1. Connections between "matrix_1" and "Arduino"
2. Connections between "joystick_1" and "Arduino"
3. Connections between "main_button_1" and "Arduino"
4. Connections between "sound_button_1" and "Arduino"
5. Connections between "green_resistor_1" and "Arduino"
6. Connections between "green_led_1" and "Arduino"
7. Connections between "red_resistor_1" and "Arduino"
8. Connections between "red_led_1" and "Arduino"
9. Connections between "buzzer_1" and "Arduino"
Deploy the firmware
#include <Arduino.h>
#include <EEPROM.h>
// The active 3-pin buzzer module is controlled as an on/off device.
enum SystemMode { MODE_SNAKE, MODE_SPAMMER, MODE_INVADERS, MODE_PONG, MODE_DINO };
enum SpamState { SPAM_WAITING, SPAM_PLAYING };
enum InvadersState { INVADERS_WAITING, INVADERS_PLAYING };
enum PongState { PONG_WAITING, PONG_PLAYING };
enum DinoState { DINO_WAITING, DINO_PLAYING };
// Forward declarations
void sendRawPacket(byte reg, byte data);
void clearMatrix();
void MAX7219init();
void drawMatrixFrame(const byte frameData[]);
void displayStaticDigit(int value);
void drawTitleIcon();
void playTone(int frequency, int duration);
bool checkButtonPress();
void showHighScoreOnce(int score);
void displayGameOverScore(int score);
void showScoreUntilButton(int score);
void switchGame(int direction);
void runSpammerLoop();
void runSnakeLoop();
void runInvadersLoop();
void runPongLoop();
void runDinoLoop();
const int DIN_PIN = 12;
const int CS_PIN = 10;
const int CLK_PIN = 11;
const int BUTTON_PIN = 2;
const int SWITCH_PIN = 3;
const int BUZZER_PIN = 4;
const int JOYX_PIN = A1;
const int JOYY_PIN = A0;
const int GREEN_LED = 5;
const int RED_LED = 6;
// A marker prevents unused EEPROM bytes from being mistaken for real high scores.
const uint32_t EEPROM_MAGIC = 0x4D47414DUL;
const int EEPROM_MAGIC_ADDR = 20;
const int EEPROM_ADDRS[5] = {24, 26, 28, 30, 32};
int highScores[5] = {0, 0, 0, 0, 0};
SystemMode currentSystemMode = MODE_SNAKE;
bool masterButtonClicked = false, lastButtonState = HIGH, lastSwitchState = HIGH;
int volumeLevel = 1, brightnessLevel = 1;
const int BRIGHTNESS_VALUES[4] = {1, 5, 10, 15};
const bool ROTATE_DISPLAY = true;
const byte FONT[10][8] = {{0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C},{0x10,0x30,0x50,0x10,0x10,0x10,0x10,0x7C},{0x3C,0x42,0x02,0x0C,0x30,0x40,0x42,0x7E},{0x3C,0x42,0x02,0x3C,0x02,0x02,0x42,0x3C},{0x08,0x18,0x28,0x48,0x7E,0x08,0x08,0x08},{0x7E,0x40,0x40,0x7C,0x02,0x02,0x42,0x3C},{0x3C,0x40,0x40,0x7C,0x42,0x42,0x42,0x3C},{0x7E,0x02,0x04,0x08,0x10,0x20,0x20,0x20},{0x3C,0x42,0x42,0x3C,0x42,0x42,0x42,0x3C},{0x3C,0x42,0x42,0x3E,0x02,0x02,0x42,0x3C}};
const byte SMILEY[8] = {0x3C,0x42,0xA5,0x81,0xA5,0x99,0x42,0x3C};
const byte ACTION_ICON[8] = {0xFF,0x81,0xBD,0xBD,0xBD,0xBD,0x81,0xFF};
const byte TROPHY_ICON[8] = {0x7E,0x42,0x7E,0x3C,0x18,0x18,0x3C,0x7E};
const byte INVADER_ICON[8] = {0x18,0x3C,0x5A,0xFF,0xFF,0x24,0x42,0x24};
const byte PONG_ICON[8] = {0x00,0x18,0x18,0x00,0x00,0x00,0x38,0x00};
const byte DINO_ICON[8] = {0x07,0x05,0x07,0x16,0x1F,0x0E,0x0A,0x0A};
SpamState currentSpamState = SPAM_WAITING;
int spamScore = 0; unsigned long spamGameStartTime = 0; const unsigned long SPAM_GAME_DURATION = 5000;
byte snakeBitmap[8] = {0}; char sx[64], sy[64]; volatile char snakeDir = 1, nextSnakeDir = 1; char snakeLength = 0; int snakeScore = 0; char snakeGameState = 0; unsigned long ts = 200, lastSnakeUpdateTime = 0;
InvadersState currentInvadersState = INVADERS_WAITING;
int playerX = 3, laserX = 0, laserY = 0, invadersScore = 0; bool invaderJoystickCentered = true, laserActive = false; unsigned long lastLaserUpdateTime = 0, lastEnemyMoveTime = 0; const int MAX_ENEMIES = 3; int enemyX[MAX_ENEMIES], enemyY[MAX_ENEMIES]; bool enemyActive[MAX_ENEMIES]; unsigned long enemySpawnTimer[MAX_ENEMIES];
PongState currentPongState = PONG_WAITING;
int pongScore = 0, paddleX = 2, pongBallX = 3, pongBallY = 3, pongBallDirX = 1, pongBallDirY = 1, pongSpeed = 300; unsigned long lastPongBallTime = 0;
DinoState currentDinoState = DINO_WAITING;
int dinoY = 7, dinoJumpPhase = 0, obstacleX = 7, obstacleHeight = 1, dinoScore = 0, dinoSpeed = 150; bool dinoJumping = false, isNight = true; unsigned long lastDinoFrameTime = 0;
void sendRawPacket(byte reg, byte data) { digitalWrite(CS_PIN, LOW); shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, reg); shiftOut(DIN_PIN, CLK_PIN, MSBFIRST, data); digitalWrite(CS_PIN, HIGH); }
void clearMatrix() { for (int i = 1; i < 9; i++) sendRawPacket(i, 0); }
void MAX7219init() { pinMode(DIN_PIN, OUTPUT); pinMode(CS_PIN, OUTPUT); pinMode(CLK_PIN, OUTPUT); digitalWrite(CS_PIN, HIGH); digitalWrite(CLK_PIN, LOW); sendRawPacket(15, 0); sendRawPacket(12, 1); sendRawPacket(9, 0); sendRawPacket(11, 7); sendRawPacket(10, BRIGHTNESS_VALUES[brightnessLevel]); clearMatrix(); }
void drawMatrixFrame(const byte frameData[]) { byte outputBuffer[8] = {0}; if (ROTATE_DISPLAY) { for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) if ((frameData[j] >> (7 - i)) & 1) outputBuffer[i] |= (1 << j); } else for (int i = 0; i < 8; i++) outputBuffer[i] = frameData[i]; for (int row = 0; row < 8; row++) sendRawPacket(row + 1, outputBuffer[row]); }
void displayStaticDigit(int value) { if (value >= 0 && value <= 9) drawMatrixFrame(FONT[value]); }
void drawTitleIcon() { if (currentSystemMode == MODE_SNAKE) drawMatrixFrame(TROPHY_ICON); else if (currentSystemMode == MODE_SPAMMER) drawMatrixFrame(SMILEY); else if (currentSystemMode == MODE_INVADERS) drawMatrixFrame(INVADER_ICON); else if (currentSystemMode == MODE_PONG) drawMatrixFrame(PONG_ICON); else drawMatrixFrame(DINO_ICON); }
void playTone(int frequency, int duration) { (void)frequency; if (volumeLevel > 0) { digitalWrite(BUZZER_PIN, HIGH); delay(duration); digitalWrite(BUZZER_PIN, LOW); } }
bool checkButtonPress() { bool state = digitalRead(BUTTON_PIN); bool pressed = false; if (state == LOW && lastButtonState == HIGH) { pressed = true; masterButtonClicked = true; delay(50); } lastButtonState = state; return pressed; }
void showScoreUntilButton(int score) {
// Wait for the button from the previous action to be released first.
while (digitalRead(BUTTON_PIN) == LOW) delay(10);
String digits = String(max(0, score));
const int glyphWidth = 8;
const int gapWidth = 1;
const int leadingBlankColumns = 8;
const int trailingBlankColumns = 8;
const int totalColumns = leadingBlankColumns +
(digits.length() * (glyphWidth + gapWidth)) +
trailingBlankColumns;
int scrollOffset = 0;
unsigned long lastFrameAt = 0;
// Shift the score by one LED column per frame, looping until the button is pressed.
while (digitalRead(BUTTON_PIN) == HIGH) {
if (millis() - lastFrameAt >= 75) {
lastFrameAt = millis();
byte frame[8] = {0};
for (int row = 0; row < 8; row++) {
for (int screenColumn = 0; screenColumn < 8; screenColumn++) {
int sourceColumn = scrollOffset + screenColumn;
int digitColumn = sourceColumn - leadingBlankColumns;
if (digitColumn >= 0 && digitColumn < digits.length() * (glyphWidth + gapWidth)) {
int digitIndex = digitColumn / (glyphWidth + gapWidth);
int columnInDigit = digitColumn % (glyphWidth + gapWidth);
if (columnInDigit < glyphWidth) {
int digit = digits.charAt(digitIndex) - '0';
if ((FONT[digit][row] >> (7 - columnInDigit)) & 0x01) {
frame[row] |= (1 << (7 - screenColumn));
}
}
}
}
}
drawMatrixFrame(frame);
scrollOffset++;
if (scrollOffset >= totalColumns) scrollOffset = 0;
}
}
delay(50); // Ignore switch bounce from the acknowledgement press.
while (digitalRead(BUTTON_PIN) == LOW) delay(10);
clearMatrix();
}
void showHighScoreOnce(int score) { digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, LOW); clearMatrix(); showScoreUntilButton(score); }
void displayGameOverScore(int score) { if (score > highScores[currentSystemMode]) { highScores[currentSystemMode] = score; EEPROM.put(EEPROM_ADDRS[currentSystemMode], score); } digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, HIGH); clearMatrix(); showScoreUntilButton(score); digitalWrite(RED_LED, LOW); masterButtonClicked = false; }
void switchGame(int direction) { int next = (int)currentSystemMode + direction; if (next > 4) next = 0; if (next < 0) next = 4; currentSystemMode = (SystemMode)next; snakeGameState = 0; snakeLength = 0; currentSpamState = SPAM_WAITING; currentInvadersState = INVADERS_WAITING; currentPongState = PONG_WAITING; currentDinoState = DINO_WAITING; masterButtonClicked = false; clearMatrix(); drawTitleIcon(); playTone(0, 50); }
void runSpammerLoop() { if (currentSpamState == SPAM_WAITING) { digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, LOW); if (masterButtonClicked) { masterButtonClicked = false; for (int i = 3; i > 0; i--) { displayStaticDigit(i); digitalWrite(RED_LED, HIGH); playTone(0, 150); delay(850); digitalWrite(RED_LED, LOW); delay(150); } drawMatrixFrame(ACTION_ICON); digitalWrite(GREEN_LED, HIGH); playTone(0, 400); clearMatrix(); spamScore = 0; currentSpamState = SPAM_PLAYING; spamGameStartTime = millis(); } } else { unsigned long elapsed = millis() - spamGameStartTime; displayStaticDigit(max(1, 5 - (int)(elapsed / 1000))); if (masterButtonClicked) { masterButtonClicked = false; spamScore++; playTone(0, 20); } if (elapsed >= SPAM_GAME_DURATION) { digitalWrite(GREEN_LED, LOW); displayGameOverScore(spamScore); drawTitleIcon(); currentSpamState = SPAM_WAITING; } } }
void runSnakeLoop() { int x = analogRead(JOYX_PIN), y = analogRead(JOYY_PIN); if (y < 200 && snakeDir != 4) nextSnakeDir = 2; if (y > 800 && snakeDir != 2) nextSnakeDir = 4; if (x < 200 && snakeDir != 3) nextSnakeDir = 1; if (x > 800 && snakeDir != 1) nextSnakeDir = 3; unsigned long now = millis(); if (snakeGameState == 0) { digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, LOW); if (masterButtonClicked) { masterButtonClicked = false; snakeGameState = 1; clearMatrix(); snakeLength = 0; } } else if (snakeGameState == 1 && now - lastSnakeUpdateTime >= ts) { lastSnakeUpdateTime = now; if (snakeLength == 0) { snakeScore = 0; snakeDir = nextSnakeDir = 1; sx[0]=3;sy[0]=3;sx[1]=3;sy[1]=4;sx[2]=3;sy[2]=5;snakeLength=3; } snakeDir = nextSnakeDir; char nx=sx[0], ny=sy[0]; if(snakeDir==1)ny--; else if(snakeDir==2)nx++; else if(snakeDir==3)ny++; else nx--; if(nx<0||nx>7||ny<0||ny>7) { snakeGameState=3; return; } for(int i=0;i<snakeLength;i++) if(nx==sx[i]&&ny==sy[i]) { snakeGameState=3; return; } for(int i=snakeLength;i>0;i--){sx[i]=sx[i-1];sy[i]=sy[i-1];} sx[0]=nx;sy[0]=ny; for(int i=0;i<8;i++)snakeBitmap[i]=0; for(int i=0;i<snakeLength;i++)snakeBitmap[sx[i]]|=(1<<sy[i]); for(int i=0;i<8;i++)sendRawPacket(i+1,snakeBitmap[i]); snakeScore++; snakeLength=min(60,(snakeScore+50)/25); } else if (snakeGameState == 3) { digitalWrite(RED_LED, HIGH); playTone(0, 400); displayGameOverScore(snakeScore); snakeGameState=0; drawTitleIcon(); } }
void runInvadersLoop() { unsigned long now=millis(); if(currentInvadersState==INVADERS_WAITING){digitalWrite(GREEN_LED,LOW);if(masterButtonClicked){masterButtonClicked=false;playerX=3;laserActive=false;invadersScore=0;for(int i=0;i<MAX_ENEMIES;i++){enemyActive[i]=true;enemyX[i]=random(0,8);enemyY[i]=0;enemySpawnTimer[i]=now+i*1200;}currentInvadersState=INVADERS_PLAYING;clearMatrix();}}else{digitalWrite(GREEN_LED,HIGH);int y=analogRead(JOYY_PIN);if(y>=200&&y<=800)invaderJoystickCentered=true;if(invaderJoystickCentered){if(y<200&&playerX<7){playerX++;invaderJoystickCentered=false;}else if(y>800&&playerX>0){playerX--;invaderJoystickCentered=false;}}if(masterButtonClicked&&!laserActive){masterButtonClicked=false;laserActive=true;laserX=playerX;laserY=6;lastLaserUpdateTime=now;playTone(0,40);}if(laserActive&&now-lastLaserUpdateTime>=70){lastLaserUpdateTime=now;if(--laserY<0)laserActive=false;}if(now-lastEnemyMoveTime>=600){lastEnemyMoveTime=now;for(int i=0;i<MAX_ENEMIES;i++)if(enemyActive[i]&&now>=enemySpawnTimer[i]&&++enemyY[i]>=7){displayGameOverScore(invadersScore);currentInvadersState=INVADERS_WAITING;drawTitleIcon();return;}}for(int i=0;i<MAX_ENEMIES;i++)if(enemyActive[i]&&now>=enemySpawnTimer[i]&&laserActive&&laserX==enemyX[i]&&laserY==enemyY[i]){laserActive=false;invadersScore++;enemyX[i]=random(0,8);enemyY[i]=0;enemySpawnTimer[i]=now+random(400,1500);}byte f[8]={0};f[7]|=1<<(7-playerX);if(laserActive)f[laserY]|=1<<(7-laserX);for(int i=0;i<MAX_ENEMIES;i++)if(enemyActive[i]&&now>=enemySpawnTimer[i])f[enemyY[i]]|=1<<(7-enemyX[i]);drawMatrixFrame(f);}}
void runPongLoop() { unsigned long now=millis(); if(currentPongState==PONG_WAITING){digitalWrite(GREEN_LED,LOW);if(masterButtonClicked){masterButtonClicked=false;paddleX=2;pongBallX=random(1,7);pongBallY=1;pongBallDirX=random(0,2)?1:-1;pongBallDirY=1;pongScore=0;pongSpeed=300;currentPongState=PONG_PLAYING;clearMatrix();}}else{digitalWrite(GREEN_LED,HIGH);int y=analogRead(JOYY_PIN);if(y<200&&paddleX<5)paddleX++;else if(y>800&&paddleX>0)paddleX--;if(now-lastPongBallTime>=pongSpeed){lastPongBallTime=now;pongBallX+=pongBallDirX;pongBallY+=pongBallDirY;if(pongBallX<=0){pongBallX=0;pongBallDirX=1;}if(pongBallX>=7){pongBallX=7;pongBallDirX=-1;}if(pongBallY<=0){pongBallY=0;pongBallDirY=1;}if(pongBallY>=7){if(pongBallX>=paddleX&&pongBallX<=paddleX+2){pongBallY=6;pongBallDirY=-1;pongScore++;pongSpeed=max(80,pongSpeed-15);}else{displayGameOverScore(pongScore);currentPongState=PONG_WAITING;drawTitleIcon();return;}}}byte f[8]={0};for(int i=0;i<3;i++)f[7]|=1<<(7-(paddleX+i));f[pongBallY]|=1<<(7-pongBallX);drawMatrixFrame(f);}}
void runDinoLoop() { unsigned long now=millis(); if(currentDinoState==DINO_WAITING){digitalWrite(GREEN_LED,LOW);if(masterButtonClicked||analogRead(JOYX_PIN)<200){masterButtonClicked=false;dinoY=7;dinoJumping=false;dinoJumpPhase=0;obstacleX=7;obstacleHeight=1;dinoScore=0;dinoSpeed=150;isNight=true;currentDinoState=DINO_PLAYING;clearMatrix();}}else{digitalWrite(GREEN_LED,HIGH);if((masterButtonClicked||analogRead(JOYX_PIN)<200)&&!dinoJumping){masterButtonClicked=false;dinoJumping=true;dinoJumpPhase=0;playTone(0,50);}if(now-lastDinoFrameTime>=dinoSpeed){lastDinoFrameTime=now;if(dinoJumping){dinoJumpPhase++;if(dinoJumpPhase<=2)dinoY=5;else if(dinoJumpPhase<=4)dinoY=3;else if(dinoJumpPhase<=6)dinoY=5;else{dinoY=7;dinoJumping=false;}}if(--obstacleX<0){obstacleX=random(7,12);obstacleHeight=random(1,3);dinoScore++;dinoSpeed=max(85,dinoSpeed-5);if(dinoScore%10==0)isNight=!isNight;}if(obstacleX==1&&((obstacleHeight==1&&dinoY>=7)||(obstacleHeight==2&&dinoY>=6))){displayGameOverScore(dinoScore);currentDinoState=DINO_WAITING;drawTitleIcon();return;}byte f[8]={0};if(dinoY>=1&&dinoY<8){f[dinoY]|=1<<6;f[dinoY-1]|=1<<6;}if(obstacleX>=0&&obstacleX<=7){f[7]|=1<<(7-obstacleX);if(obstacleHeight==2)f[6]|=1<<(7-obstacleX);}if(!isNight)for(int i=0;i<8;i++)f[i]=~f[i];drawMatrixFrame(f);}}}
void setup(){pinMode(BUTTON_PIN,INPUT_PULLUP);pinMode(SWITCH_PIN,INPUT_PULLUP);pinMode(BUZZER_PIN,OUTPUT);digitalWrite(BUZZER_PIN,LOW);pinMode(GREEN_LED,OUTPUT);pinMode(RED_LED,OUTPUT);randomSeed(analogRead(A5));MAX7219init();uint32_t storedMagic=0;EEPROM.get(EEPROM_MAGIC_ADDR,storedMagic);if(storedMagic!=EEPROM_MAGIC){for(int i=0;i<5;i++){highScores[i]=0;EEPROM.put(EEPROM_ADDRS[i],highScores[i]);}EEPROM.put(EEPROM_MAGIC_ADDR,EEPROM_MAGIC);}else{for(int i=0;i<5;i++){EEPROM.get(EEPROM_ADDRS[i],highScores[i]);if(highScores[i]<0||highScores[i]>10000){highScores[i]=0;EEPROM.put(EEPROM_ADDRS[i],highScores[i]);}}}drawTitleIcon();}
void loop(){bool title=(currentSystemMode==MODE_SNAKE&&snakeGameState==0)||(currentSystemMode==MODE_SPAMMER&¤tSpamState==SPAM_WAITING)||(currentSystemMode==MODE_INVADERS&¤tInvadersState==INVADERS_WAITING)||(currentSystemMode==MODE_PONG&¤tPongState==PONG_WAITING)||(currentSystemMode==MODE_DINO&¤tDinoState==DINO_WAITING);if(title){bool sw=digitalRead(SWITCH_PIN);if(sw==LOW&&lastSwitchState==HIGH){volumeLevel=(volumeLevel+1)%2;if(volumeLevel)playTone(0,100);delay(200);}lastSwitchState=sw;static unsigned long lastNav=0;int x=analogRead(JOYX_PIN),y=analogRead(JOYY_PIN);if(millis()-lastNav>300){if(y<200){switchGame(1);lastNav=millis();}else if(y>800){switchGame(-1);lastNav=millis();}else if(x<200){brightnessLevel=(brightnessLevel+1)%4;sendRawPacket(10,BRIGHTNESS_VALUES[brightnessLevel]);lastNav=millis();}else if(x>800){showHighScoreOnce(highScores[currentSystemMode]);drawTitleIcon();lastNav=millis();}}}else lastSwitchState=digitalRead(SWITCH_PIN);checkButtonPress();if(currentSystemMode==MODE_SNAKE)runSnakeLoop();else if(currentSystemMode==MODE_SPAMMER)runSpammerLoop();else if(currentSystemMode==MODE_INVADERS)runInvadersLoop();else if(currentSystemMode==MODE_PONG)runPongLoop();else runDinoLoop();}Download project files
Remix this project
Make it yours in one click
Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.




