How can I have a button switch the animation on an LED matrix?

I want to have a button switch the animation that is running. The button works but it doesn’t update value of the button when the animation is running. How can I have the button value constantly update while the animation is running? here is my code:

#include <FastLED.h>

#include "Plasma.cpp"
#include "TestPattern.cpp"
#include "Snake.cpp"
#include "Twinkle.cpp"
#include "DeadChannel.cpp"
#include "Bouncy.cpp"
#include "HiRez.cpp"
#include "Boxes.cpp"
#include "Life.cpp"
#include "Sprite.cpp"

#define WIDTH 14
#define HEIGHT 14
#define NUM_LEDS WIDTH * HEIGHT

#define DATA_PIN 3

CRGB leds[NUM_LEDS];
const int  buttonPin = 5;    

// Variables will change:
int buttonPushCounter = 0;   
int buttonState = 0; 
int lastButtonState=0;        
 

void setup() {
  // put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(8, OUTPUT);


    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
    Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
//    TestPattern testPattern(leds, WIDTH, HEIGHT);
//    testPatt.start();

 buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
     
    } 
    
  }
 
  lastButtonState = buttonState;

  if (buttonPushCounter  == 1) {


digitalWrite(8,HIGH);
doTwinkle();

   
   
  } else if (buttonPushCounter  == 2){
    

digitalWrite(9,HIGH);
doSnake();

      
  } else if (buttonPushCounter  == 3){


digitalWrite(10,HIGH);

doPlasma();
    
    buttonPushCounter = 1;
  } 
    
   
    
    
}

void doDeadChannel() {
    DeadChannel deadChannel(leds, WIDTH, HEIGHT);
    deadChannel.start();
}

void doPlasma() {
    Plasma plasma(leds, WIDTH, HEIGHT);
    plasma.start();
}

void doTwinkle() {
    Twinkle twinkle(leds, WIDTH, HEIGHT, true, true);
    twinkle.start();
}

void doSnake() {
    Snake snake(leds, WIDTH, HEIGHT);
    snake.start();
}

void doLife() {
    Life life(leds, WIDTH, HEIGHT, 56);
    life.start();
}

void doSprite() {
    Sprite sprite(leds, WIDTH, HEIGHT);
    sprite.start();
}

Thats the main part here is the parts that it refers to

Twinkle:

/*
 * Effect implementation for the GauntletII project.
 */

#include "Effect.h"


#define MAX_TWINKS 25
#define OFFSET 0xB000

typedef struct Twink {
    short x;
    short y;
} Twink;

class Twinkle : public Effect {
    
private:
    short numTwinks;
    bool colour;
    bool cycleSaturation;
    
public:
    Twinkle(CRGB *leds, int width, int height, bool colour, bool cycleSaturation) :
        Effect(leds, width, height),
        colour(colour),
        cycleSaturation(cycleSaturation),
        numTwinks(0) {
    }
    
    void start() {
        for (uint16_t frame = 0x0000, iterations = 0; iterations < 2250; frame += 0x20, iterations++) {
            for (int i = 0; i < width * height; i++) {
              
                if (leds[i]) {
                    leds[i].fadeToBlackBy(50);
                    if (!leds[i]) {
                        numTwinks--;
                    }
                } else {
                    if (random(56) == 0) {
                        numTwinks++;
                        if (colour) {
                            if (cycleSaturation) {
                                uint8_t saturation = (sin16(frame + OFFSET) >> 8) + 128;
                                leds[i] = CHSV(random(255), saturation, 255);
                            } else {
                                leds[i] = CHSV(random(255), random(128, 255), 255);
                            }
                        } else {
                            leds[i] = CRGB::White;
                        }
                    }
                }
            }
            LEDS.show();
        }
    }
};

Snake:

/*
 * Effect implementation for the GauntletII project.
 */

#include "Effect.h"

class Snake : public Effect {
private:
    
    static const byte SNAKE_LENGTH = 16;
    
    enum Direction {
        UP, DOWN, LEFT, RIGHT
    };
    
    struct Pixel {
        uint8_t x;
        uint8_t y;
    };
    
    CRGB colours[SNAKE_LENGTH];
    uint8_t initialHue;
    
    Pixel pixels[SNAKE_LENGTH];
    
    Direction direction;
    
    void newDirection() {
        switch (direction) {
            case UP:
            case DOWN:
                direction = random(0, 2) == 1 ? RIGHT : LEFT;
                break;
                
            case LEFT:
            case RIGHT:
                direction = random(0, 2) == 1 ? DOWN : UP;
                
            default:
                break;
        }
    }
    
    void shuffleDown() {
        for (byte i = SNAKE_LENGTH - 1; i > 0; i--) {
            pixels[i] = pixels[i - 1];
        }
    }
    
public:
    Snake(CRGB *leds, int width, int height) : Effect(leds, width, height), initialHue(0) {
        direction = UP;
        for (int i = 0; i < SNAKE_LENGTH; i++) {
            pixels[i].x = 0;
            pixels[i].y = 0;
        }
    }
    
    void start() {
        clearLeds();
        for (int frameNo = 0; frameNo < 1000; frameNo++) {
            shuffleDown();
            if (random(10) > 6) {
                newDirection();
            }
            switch (direction) {
                case UP:
                    pixels[0].y = (pixels[0].y + 1) % height;
                    break;
                case LEFT:
                    pixels[0].x = (pixels[0].x + 1) % width;
                    break;
                case DOWN:
                    pixels[0].y = pixels[0].y == 0 ? height - 1 : pixels[0].y - 1;
                    break;
                case RIGHT:
                    pixels[0].x = pixels[0].x == 0 ? width - 1 : pixels[0].x - 1;
                    break;
            }
            fill_rainbow(colours, SNAKE_LENGTH, initialHue++);
            for (byte i = 0; i < SNAKE_LENGTH; i++) {
                pixel(pixels[i].x, pixels[i].y) = colours[i] %= (255 - i * (255 / SNAKE_LENGTH));
            }
            LEDS.show();
            delay(30);
            clearLeds();
        }
    }
};

Bugflip:
The button works but it doesn't update value of the button when the animation is running.

Obviously! your animations are full of delays.

Bugflip:
How can I have the button value constantly update while the animation is running?

In your case using an interrupt to register your button presses might be easier OR you could try implementing several things at the same time

I tried the interrupt thing but it didn’t work it does the same thing. It starts the program with a button click but wont do anything when the animations are running. Here is the part I changed from the program in the original question.

volatile int buttonstate;
volatile int buttoncount=1;


void setup() {
  pinMode(2, INPUT);
 attachInterrupt(0,buttonPressed, FALLING);

    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
}

void loop() {

  switch (buttoncount){
    case 1:
    doTwinkle();
    break;
    case 2:
    doSnake();
    break;
    case 3:
    doSprite();
    break;
  }



}
void buttonPressed(){
  buttonstate= digitalRead(2);
  if(buttonstate==HIGH){
    buttonstate = false;
    if (buttoncount<3){
       buttoncount++;
    }
  
  }else{
    buttonstate = true;
    
    if (buttoncount>3){
    
      buttoncount=1;
    }
  }
}

oh and what do you mean there are so many delays I don’t see any, and how can I remove them?

Bugflip:
I tried the interrupt thing but it didn’t work it does the same thing. It starts the program with a button click but wont do anything when the animations are running. Here is the part I changed from the program in the original question.

Interesting… and I can see why (again its because your patterns are blocking functions).

What you could do if you still want to make used of interrupts is something like (you need to add in the libraries)?

volatile uint8_t buttoncount=0;
const uint8_t T_ms_debounce = 100; //100ms debounce time
unsigned long oldtime;
uint8_t buttonstate;


void setup() {
  pinMode(2, INPUT);
 attachInterrupt(digitalPinToInterrupt(2),buttonPressed, CHANGE);

    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
}

void loop() {
	doTwinkle(buttoncount);
	doSnake(buttoncount);
	doSprite(buttoncount);

}
void buttonPressed(){
  if(digitalRead(2)==LOW){
	oldtime = millis();
  }
  else if(millis() - oldtime> T_ms_debounce){
	if(buttoncount<4)++buttoncount;
	else buttoncount = 0; 
  }
}

what’s happenning here is that “buttoncount” gets passed to your pattern routines and what you would need to add to your pattern routines is a check for “buttoncount” in its loop(s).

if “buttoncount” matches the pattern (e.g Twinkle =1 ,Snake =2, etc), it continues the current pattern else it exits the pattern routine to check the next pattern routine.

oh and what do you mean there are so many delays I don’t see any

Well, here are 1000 delay()s

      for (int frameNo = 0; frameNo < 1000; frameNo++)
      {

//other code here

        delay(30);
        clearLeds();
      }

Getting rid of them involves using millis() or micros() for timing.
Break the code into steps, save the start time when the step starts then check frequently (each time through loop() is good) whether the time now minus the start time is greater than the required wait period. If so, then move on to the next step. If not go round loop() again, perhaps reading inputs along the way.

See Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

sherzaad:
what's happenning here is that "buttoncount" gets passed to your pattern routines and what you would need to add to your pattern routines is a check for "buttoncount" in its loop(s).

if "buttoncount" matches the pattern (e.g Twinkle =1 ,Snake =2, etc), it continues the current pattern else it exits the pattern routine to check the next pattern routine.

When the button count changes how do I make it go back to the main code and check for the next pattern.

@Bugflip - until you restructure / rewrite the code to be non-blocking, every other "solution" is going to be a kludge. Take a look at this Adafruit Tutorial. You don't need to go as far as they did in defining new classes to inherit from the base NeoPixel class, but the concept they present of "Deconstructing the Loop" is what you need to do.