#include <TM1628.h>
#include <Servo.h>
// ---------------- DISPLAY ----------------
#define DATA_PIN 7
#define CLOCK_PIN 6
#define STROBE_PIN 8
TM1628 display(DATA_PIN, CLOCK_PIN, STROBE_PIN);
// ---------------- LEDS ----------------
int leds[] = {A1, A2, A3, A4, A5, 12};
// ---------------- BUZZER ----------------
int buzzer = 11;
// ---------------- BUTTONS ----------------
int btnLeft = 2;
int btnRight = 3;
// ---------------- SERVOS ----------------
Servo servoLeft;
Servo servoRight;
// ---------------- GAME LOGIC ----------------
int currentLed = -1;
unsigned long lastChange = 0;
int speed = 400;
// ---------------- SCORE ----------------
int score = 0;
unsigned long lastScoreTime = 0;
int scoreStep = 1;
// ---------------- DISCO / VISUAL EFFECTS ----------------
byte discoEnd[] = {1, 3, 11, 13, 7, 9};
int discoFrame = 0;
unsigned long discoTime = 0;
int discoSpeed = 90;
// ---------------- NUMBERS (7-Segment Mapping) ----------------
const byte numbers[] = {
0b00111111, 0b00000110, 0b01011011, 0b01001111,
0b01100110, 0b01101101, 0b01111101, 0b00000111,
0b01111111, 0b01101111
};
void setup() {
display.begin(true, 7);
clearAll();
for(int i=0; i<6; i++) pinMode(leds[i], OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(btnLeft, INPUT_PULLUP);
pinMode(btnRight, INPUT_PULLUP);
servoLeft.attach(9);
servoRight.attach(10);
servoLeft.write(20);
servoRight.write(160);
randomSeed(analogRead(A0));
}
void loop() {
// Random LED logic
if(millis() - lastChange > (unsigned long)speed){
lastChange = millis();
for(int i=0; i<6; i++) digitalWrite(leds[i], LOW);
currentLed = random(0, 6);
digitalWrite(leds[currentLed], HIGH);
speed = max(120, speed - 1);
}
// Input Handling
if(digitalRead(btnLeft) == LOW){
flipperAction(true);
}
if(digitalRead(btnRight) == LOW){
flipperAction(false);
}
runDisco();
}
// ---------------- FLIPPER ----------------
void flipperAction(bool left){
if(left){
servoLeft.write(70);
delay(60);
servoLeft.write(20);
} else {
servoRight.write(110);
delay(60);
servoRight.write(160);
}
hitEffect();
addScore();
}
// ---------------- HIT EFFECT ----------------
void hitEffect(){
digitalWrite(leds[currentLed], LOW);
for(int f = 1000; f < 2000; f += 150){
tone(buzzer, f, 10);
delay(5);
}
for(int i=0; i<6; i++) digitalWrite(leds[i], HIGH);
delay(40);
for(int i=0; i<6; i++) digitalWrite(leds[i], LOW);
}
// ---------------- SCORE ----------------
void addScore(){
if(millis() - lastScoreTime < 200) return;
lastScoreTime = millis();
score += scoreStep;
if(score > 9999) score = 0;
// Progression: Increase points per hit every 10 points
if(score % 10 == 0 && scoreStep < 5){
scoreStep++;
}
discoSpeed = max(50, 90 - score);
discoWaveEffect();
numberWaveEffect(score);
comboEffect();
}
// ---------------- DISCO ANIMATION ----------------
void runDisco(){
if(millis() - discoTime >= (unsigned long)discoSpeed){
discoTime = millis();
for(int i=0; i<6; i++){
setIcon(discoEnd[i], 0);
}
setIcon(discoEnd[discoFrame], 2);
discoFrame++;
if(discoFrame >= 6) discoFrame = 0;
}
}
// ---------------- DISCO WAVE EFFECT ----------------
void discoWaveEffect(){
for(int i=0; i<6; i++){
setIcon(discoEnd[i], 2);
tone(buzzer, 1200 + i*120, 10);
delay(12);
}
for(int i=5; i>=0; i--){
setIcon(discoEnd[i], 0);
delay(10);
}
}
// ---------------- NUMBER WAVE EFFECT ----------------
void numberWaveEffect(int value){
int d1 = value % 10;
int d2 = (value / 10) % 10;
int d3 = (value / 100) % 10;
int d4 = (value / 1000) % 10;
byte digits[4] = {d1, d2, d3, d4};
for(int seg=0; seg<7; seg++){
byte val = 0;
if(bitRead(numbers[digits[0]], seg)) val += 1;
if(bitRead(numbers[digits[1]], seg)) val += 2;
if(bitRead(numbers[digits[2]], seg)) val += 128;
if(bitRead(numbers[digits[3]], seg)) val += 4;
display.setSegments(val, seg);
delay(18);
}
}
// ---------------- COMBO EFFECTS ----------------
void comboEffect(){
if(score % 50 == 0){
// 💥 Explosion effect
for(int i=0; i<3; i++){
display.setSegments(255, i);
}
tone(buzzer, 2500, 100);
delay(120);
clearAll();
}
else if(score % 20 == 0){
// ⚡ Strong flash
display.setSegments(255, 0);
display.setSegments(255, 1);
tone(buzzer, 2000, 80);
delay(80);
}
else if(score % 10 == 0){
// ✨ Light flash
display.setSegments(255, 0);
tone(buzzer, 1500, 50);
delay(50);
}
}
// ---------------- LOW LEVEL COMMUNICATION ----------------
void sendRawCommand(byte cmd) {
digitalWrite(STROBE_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, cmd);
digitalWrite(STROBE_PIN, HIGH);
}
void setIcon(byte address, byte value) {
sendRawCommand(0x44);
digitalWrite(STROBE_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0xC0 + address);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, value);
digitalWrite(STROBE_PIN, HIGH);
}
// ---------------- CLEAR DISPLAY ----------------
void clearAll() {
for (int i = 0; i <= 20; i++) {
display.setSegments(0x00, i);
}
sendRawCommand(0x40);
digitalWrite(STROBE_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0xC0);
for (int i = 0; i < 16; i++) shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, 0x00);
digitalWrite(STROBE_PIN, HIGH);
}
Comments