Code for Individually Addressable RGB led strip not functioning as expected

I'm trying to display individual lights on an led strip as they are created which animate down the length of the strip. I'm doing this by using a custom class "Creature" to hold a colour, speed and array position. I set up a Read function to monitor button presses which decide colour and speed, then I use the function MakeNewCreature to set an entry in an array of creatures to the chosen values. Then I have an Animate function run through the array of leds on the strip and determine which ones currently align with a creature's array position, and then set the colour of that led. At the end of each run through this loop the led states are displayed (FastLED.show()).

The expected result is to have multiple dots of light moving along the strip at a time. The result I'm getting is a single dot crawling along the strip. If another creature is created through button presses then the currently displaying creature seems to stop displaying until the new creature has run to the end of the strip, at which point the first creature continues from the position is stopped at.

I'm not sure why I'm getting this behavior, it's likely something funny I've done (misunderstanding of how the code works) but I can't reconcile my code with this result. If someone would help me understand why it's doing what it's doing I'd be grateful!

I'm working with an arduino uno

Here is the code I've written (except for the debounce piece taken from a tutorial):

#include <FastLED.h>


#define DATA_PIN     13
#define NUM_LEDS    60
#define BRIGHTNESS  64
#define MAX_CREATURES 10
#define LED_TYPE    NEOPIXEL
#define COLOR_ORDER GRB
#define NUMBER_OF_BUTTONS 2
#define SPEED_MULTIPLIER 100


class Creature{
  
  public:
  int speedDelay;
  int colour1,colour2;
  int arrayPosition;
  int counter;
  bool alive;
  
  Creature(){}
  
  Creature(int newColour1,int newColour2, int newSpeed){
    colour1 = newColour1;
    colour2 = newColour2;
    speedDelay = newSpeed;
    arrayPosition = 0;
    counter = 0;
    alive = true;
  }
  
  int locomotion(){
    if(counter>=speedDelay){
      arrayPosition++;
      counter = 0;
    }
    else
      counter++;
      return arrayPosition;
  }
};


Creature creatures[MAX_CREATURES];
CRGB leds[NUM_LEDS];


int buttons[] = {
  2,3,4,5
};
CRGB colours[] = {
  CRGB::Red,CRGB::Blue,CRGB::Green,CRGB::Yellow
};
int buttonState=0;
int tempSpeed,tempColour1,tempColour2;
int buttonCounter;
int creatureCounter;
bool makeNewCreature;

int debounce(int pin)
{
  int state, previous_state;
  previous_state = digitalRead(pin); 
  for(int i = 0; i < 25; i++)
  {
    delay(3);                       
    state = digitalRead(pin);       
    if( state != previous_state)
    {
      i = 0;                  
      previous_state = state;       
    }
  }
  return state;
}

void setup() {
            delay( 3000 ); // power-up safety delay
    FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
    FastLED.setBrightness(  BRIGHTNESS );
    Serial.begin(9600);
    for(int i = 0; i<NUMBER_OF_BUTTONS;i++){
    pinMode(buttons[i],INPUT);
  }
}

void loop() {
    Read();
    AnimateCreatures();
}

void AnimateCreatures(){
  for(int led = 0; led<NUM_LEDS;led++){
      for(int a = 0; a<MAX_CREATURES;a++){
        if(creatures[a].alive){
           if(creatures[a].locomotion() == led){
            leds[led] += colours[creatures[a].colour1]+colours[creatures[a].colour2];
           }
           else{
             leds[led] = CRGB::Black;
           }
          if (creatures[a].locomotion()>=60){
             creatures[a].alive = false;
           }
        }
      }
  }
  FastLED.show();
}

void MakeNewCreature(){
  Creature newCreature(tempColour1,tempColour2,tempSpeed);
  creatures[creatureCounter] = newCreature;
  creatureCounter++;
  if(creatureCounter>=MAX_CREATURES){
    creatureCounter=0;
  }

}

void Read(){

  
  for(int i = 0; i<NUMBER_OF_BUTTONS;i++){
    if(debounce(buttons[i])==HIGH){
      Serial.println(String("Button Pressed: ")+i);
     switch (buttonCounter){
       case 0:
       tempColour1 = i;
       break;
       case 1:
       tempColour2=i;
       break;
       case 2:
       tempSpeed=(i+1)*SPEED_MULTIPLIER;
       break;
     }
     buttonCounter++;
     if(buttonCounter>=3){
       buttonCounter=0;
       MakeNewCreature();
     }
    }
  }
}

Each time you update the LEDs, you are looking at a single "creature", turning on one LED, and turning all other LEDs off. So, when you have two creatures, you turn on a single LED, corresponding to the first creature, and turn all the other off. Then you turn on the one LED corresponding to the second creature, and turn all the other LEDs off, including the one corresponding to the one for the first creature. Before turning any LED off, you need to make sure there is NO creature which wants that LED turned on.

Regards,
Ray L.

  Creature newCreature(tempColour1,tempColour2,tempSpeed);
  creatures[creatureCounter] = newCreature;

This creature goes out of scope when the function ends. You can't use that creature later.

 creatures[creatureCounter] = new Creature(tempColour1,tempColour2,tempSpeed);

This creature hangs around, but you need to change the type of creatures to pointer to Creature, not Creature.

RayLivingston:
Each time you update the LEDs, you are looking at a single "creature", turning on one LED, and turning all other LEDs off. So, when you have two creatures, you turn on a single LED, corresponding to the first creature, and turn all the other off. Then you turn on the one LED corresponding to the second creature, and turn all the other LEDs off, including the one corresponding to the one for the first creature. Before turning any LED off, you need to make sure there is NO creature which wants that LED turned on.

Thanks! I set up an array to hold an int corresponding to the creature assigned to the led, and a conditional to check if that creature is still present on the led. I don't know why I couldn't see that I was overwriting the state of the leds each time.

Anyway it now displays the behavior I expected!

PaulS:

  Creature newCreature(tempColour1,tempColour2,tempSpeed);

creatures[creatureCounter] = newCreature;



This creature goes out of scope when the function ends. You can't use that creature later.



creatures[creatureCounter] = new Creature(tempColour1,tempColour2,tempSpeed);



This creature hangs around, but you need to change the type of creatures to pointer to Creature, not Creature.

I don't understand why this piece needs to change, at the moment the creatures display as expected so it seems to me the data is preserved. Sorry I don't know much about pointers - attempting to make the change you suggested resulted in the piece no longer functioning. It's likely there's a problem you're able to see that I'm unaware of.