// anim2.cpp - CLEAN CLASSIC ARCADE SCROLLING (NO FX)
#include <MD_MAX72xx.h>
#include <MD_Parola.h>
#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;
}
}