// anim2.cpp - CLEAN CLASSIC ARCADE SCROLLING (NO FX) #include #include #include "main.h" // ────── TEXT ARRAYS ────── const char* const textsPanel1[] = { " INSERT COIN ", " GAME OVER ", " PLAYER ONE READY ", " PLAYER TWO READY ", " PRESS START ", " WELCOME TO ARCADE ", " FREE PLAY ", " 1 OR 2 PLAYERS ", }; const char* const textsPanel2[] = { " 1UP HIGH SCORE ", " PLAYER 1 001234 ", " PLAYER 2 000890 ", " BONUS AT 10000 PTS ", " Emulator ", " RETRO GAME ", " ULTIMATE RETRO CABINET ", " THANKS FOR PLAYING! ", }; const uint8_t numTexts1 = sizeof(textsPanel1) / sizeof(textsPanel1[0]); const uint8_t numTexts2 = sizeof(textsPanel2) / sizeof(textsPanel2[0]); // ────── Two independent Parola displays ────── MD_Parola p1 = MD_Parola(HARDWARE_TYPE, DATA_PIN1, CLK_PIN1, CS_PIN1, MAX_DEVICES); MD_Parola p2 = MD_Parola(HARDWARE_TYPE, DATA_PIN2, CLK_PIN2, CS_PIN2, MAX_DEVICES); // ────── Animation control ────── uint8_t currentText1 = 0; uint8_t currentText2 = 0; unsigned long nextChange1 = 0; unsigned long nextChange2 = 0; const uint16_t SCROLL_SPEED = 40; // Adjust speed here const uint16_t PAUSE_TIME = 1; // Pause when text is centered const uint16_t CHANGE_DELAY = 5000; // How long before next message (12 seconds) bool setupDone = false; void setupAnimText() { p1.begin(); p1.setIntensity(MATRIX_INTENSITY); p1.displayClear(); p1.displayText((char*)textsPanel1[0], PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_SCROLL_LEFT, PA_SCROLL_LEFT); p2.begin(); p2.setIntensity(MATRIX_INTENSITY); p2.displayClear(); p2.displayText((char*)textsPanel2[0], PA_CENTER, SCROLL_SPEED + 10, PAUSE_TIME, PA_SCROLL_LEFT, PA_SCROLL_LEFT); nextChange1 = millis() + CHANGE_DELAY; nextChange2 = millis() + CHANGE_DELAY + 4000; // slight offset so they don't sync perfectly setupDone = true; Serial.println(F("Classic Arcade Marquee Started - Pure Scrolling")); } void animtext() { if (!setupDone) setupAnimText(); unsigned long now = millis(); // THESE TWO LINES ARE MANDATORY — THEY MAKE THE TEXT MOVE! p1.displayAnimate(); // ← THIS MOVES PANEL 1 p2.displayAnimate(); // ← THIS MOVES PANEL 2 // Change message when time is up if (now >= nextChange1) { currentText1 = (currentText1 + 1) % numTexts1; p1.displayText((char*)textsPanel1[currentText1], PA_CENTER, SCROLL_SPEED, PAUSE_TIME, PA_SCROLL_LEFT, PA_SCROLL_LEFT); nextChange1 = now + CHANGE_DELAY; } if (now >= nextChange2) { currentText2 = (currentText2 + 1) % numTexts2; p2.displayText((char*)textsPanel2[currentText2], PA_CENTER, SCROLL_SPEED + 10, PAUSE_TIME, PA_SCROLL_LEFT, PA_SCROLL_LEFT); nextChange2 = now + CHANGE_DELAY + random(0, 6000); } } //.............................................................................. // ────────────────────────────────────────────────────────────── // RETRO SYSTEMS — ALL CAPS — NO TRAILING SPACES — PERFECT CENTERING // ────────────────────────────────────────────────────────────── const char* const topBrands[] = { " ATARI", " NINTENDO", " SEGA", " NAMCO", " CAPCOM", " KONAMI", " TAITO", " 3DO", " AMIGA", " ARCADE", " MAME", " C64", " COLECO", " DREAMCAST", " FAMICOM", " FBNEO", " GAMEGEAR", " GBA", " GX4000", " LYNX" }; const char* const bottomBrands[] = { " INTELLIVISION", " GBC", " MASTERSYSTEM", " MEGADRIVE", " MSX1", " N64", " NAOMI", " NDS", " NEOGEO", " NES", " OPENBOR", " PC", " VECTREX", " SEGACD", " TURBOGRAFX", " PSX", " PSP", " SWITCH", " X68000", " SNES" }; const uint8_t numTop = sizeof(topBrands) / sizeof(topBrands[0]); const uint8_t numBottom = sizeof(bottomBrands) / sizeof(bottomBrands[0]); uint8_t idxTop = 0; uint8_t idxBottom = 0; unsigned long nextTop = 0; unsigned long nextBottom = 0; bool marqueeReady = false; void setupMarquee() { p1.begin(); p1.setIntensity(MATRIX_INTENSITY); p1.displayClear(); p1.displayText((char*)topBrands[0], PA_CENTER, 40, 2500, PA_SCROLL_LEFT, PA_SCROLL_LEFT); p2.begin(); p2.setIntensity(MATRIX_INTENSITY); p2.displayClear(); p2.displayText((char*)bottomBrands[0], PA_CENTER, 46, 2200, PA_SCROLL_LEFT, PA_SCROLL_LEFT); nextTop = millis() + 7000; nextBottom = millis() + 7500; // slight offset = more natural marqueeReady = true; Serial.println(F("RETRO MARQUEE STARTED - CLEAN & PERFECT")); } void animtext2() { if (!marqueeReady) setupMarquee(); unsigned long now = millis(); // THESE TWO LINES MAKE TEXT MOVE — NEVER REMOVE p1.displayAnimate(); p2.displayAnimate(); // TOP PANEL if (now >= nextTop) { idxTop = (idxTop + 1) % numTop; p1.displayText((char*)topBrands[idxTop], PA_CENTER, 40, 2500, PA_SCROLL_LEFT, PA_SCROLL_LEFT); nextTop = now + 7000; // ← use 'now', not millis() again! } // BOTTOM PANEL if (now >= nextBottom) { idxBottom = (idxBottom + 1) % numBottom; p2.displayText((char*)bottomBrands[idxBottom], PA_CENTER, 46, 2200, PA_SCROLL_LEFT, PA_SCROLL_LEFT); nextBottom = now + 7000; } }