pbnj

snippet #3

// 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;
  }
}