Display objects stored in an ArrayList one after the other (Animation)

Hello everyone,

What are the different solutions (or the easiest one for a beginner to master) to display some objects stored in an array (or in the case of my sketch in an ArrayList) one after the other and rather than all at once ?
I’m working on this sketch with some flashing / fading rectangles. I’m looping through an ArrayList to display them on the screen. I’d like to understand how to control the moment when each object is diplayed. Should I use millis() ? I don’t know if I’m clear (sorry English is not my first language!).
Here is my code. At the moment all the rectangles are displayed at the same time :

class Flashr {

float x;
float y;
float rsize;
float trans = 0.5; // 
float dtrans = -0.01; 

Flashr (float fx, float fy, float frsize) {
    x = fx;
    y = fy;
    rsize = frsize;
  }

void flashrect(){
  float a = map(trans, 0, 1, 0, 255);
  fill(0, 0, 255, a);
  trans += dtrans;
  trans = constrain(trans, 0, 1);
  if (trans == 0) {
    dtrans = 0.01;
  } else if 
    (trans > 0.5){
    dtrans = -0.01;
  }
  rect(x, y, rsize, rsize);
 }
}
// end class

int num = 30;

Flashr randomFlashr() {
  return new Flashr(random(width), random(0, 150), 50);
}

ArrayList <Flashr> flashList;

void setup() {
  size(600, 600);
  smooth();
  flashList = new ArrayList<Flashr>();
  int i = 0;
  while (i < num) {
    flashList.add(randomFlashr());
    i++;
  }
}

void draw() {
  background(255);
  noStroke();
  //for (Flashr f : flashList) {
  for (int j = 0; j< flashList.size(); j++) {
    Flashr f = flashList.get(j);
    f.flashrect();
  }
}

From what I can tell, your trans variable determines when each rectangle “flashes”. If you want to make them flash at different times, you can allow the trans variable to be set to a value between 0 and 1 in the Flashr constructor, then have the randomFlashr method initialize a Flashr's trans value to a random float between 0 and 1. If you want each Flashr to spawn in at a different time, you need to fill the flashList in draw() so you can fill it dynamically. For example, this code, if placed at the beginning of draw(), will add a new Flashr every frame until the number of Flashr's reach num.

  // beginning of draw
  if (flashList.size() < num) {
    flashList.add(randomFlashr());
  }

If you want more precise control over when each Flashr is added, like to the millisecond, the question isn’t whether you should use millis(), it is how you should use millis(). Of course, there is no one answer to this question. One solution I came up with uses four integers, elapsedTime, prevTime, deltaTime and timePerFlashr, where elapsedTime is a variable to store the time after a new Flashr was created, deltaTime is the amount of milliseconds that pass every frame, prevTime is the value of millis() from the previous frame, and timePerFlashr is how long the program should wait before spawning a new Flashr. The basic logic is, if elapsed time increases past the time to wait between spawning Flashrs, spawn Flashrs and decrease elapsed time until the condition is not true anymore.

  // beginning of draw
  // get the time that passed since the last frame in milliseconds
  int currentTime = millis();
  deltaTime = currentTime - prevTime;
  prevTime = currentTime;
  // increase elapsed time by the change in time
  elapsedTime += deltaTime;
  while (elapsedTime >= timePerFlashr && flashList.size() < num) {
    flashList.add(randomFlashr());
    // the logic behind subtracting this value every time you spawn a new Flashr
    // instead of resetting to 0 is that you can spawn multiple Flashrs per frame
    elapsedTime -= timePerFlashr;
  }

Keep in mind that this solution is limited by the framerate of the sketch. Even if millis() is accurate to the millisecond, the program only checks to spawn new Flashr's once per frame.

1 Like

In theory another solution would be to get rid of the for loop in draw() and just use j as a global variable and say j++ after a certain time has passed or with a lower frameRate

This works because draw() in itself loops automatically

ArrayList<Flashr> flashList = new ArrayList<Flashr>();
int j = 0;
int timer; 

void setup() {
  size(600, 600);
  smooth();

  int i = 0;
  int num = 30;
  while (i < num) {
    flashList.add(randomFlashr());
    i++;
  }

  // frameRate(1);
  timer=millis();
}

void draw() {
  background(255);
  noStroke();
  //for (Flashr f : flashList) {
  //for (int j = 0; j< flashList.size(); j++) {
  Flashr f = flashList.get(j);
  f.flashrect();
  // }

  if (millis()-timer > 2600) {
    timer=millis();
    if (j < flashList.size()-1) {
      j++;
    }
  }
}

Flashr randomFlashr() {
  return 
    new Flashr(random(width), random(0, 150), 50);
}

//===========================================================================

class Flashr {

  float x;
  float y;
  float rsize;
  float trans = 0.5; // 
  float dtrans = -0.01; 

  Flashr (float fx, float fy, float frsize) {
    x = fx;
    y = fy;
    rsize = frsize;
  }//constr

  void flashrect() {
    float a = map(trans, 0, 1, 0, 255);
    fill(0, 0, 255, a);
    trans += dtrans;
    trans = constrain(trans, 0, 1);
    if (trans == 0) {
      dtrans = 0.01;
    } else if 
      (trans > 0.5) {
      dtrans = -0.01;
    }
    rect(x, y, rsize, rsize);
  }
} // end class
//

1 Like

Thank you very much for your answers and suggestions ! It’s very helpful. I’m going to try them out.

1 Like

here is my take on the project!
I used classes to make them. It works by using the frameCount value and using
frameCount + offSet % interval (I named the variable stage)
it gives a 0 to interval value, which I plug into this equation:

float v = sin(stage/interval * PI);
fill(0,0,255*v); 

it helps to remove the middle values, which all look quite similar and boring.

Code
ArrayList<blinker> blinkers = new ArrayList<blinker>();
void setup() {
  size(600,600);
  for(int i = 0; i < 40; i++) blinkers.add(new blinker(random(width-20),random(height-20),20,random(30,100),random(50)));
} 
void draw() {
  background(0);
  for(blinker blink : blinkers) {
    blink.display();
  }
}

class blinker {
  float x, y, a, interval,offSet;
  blinker(float _x, float _y, float _a, float _interval, float _offSet) {
    x = _x; y = _y; a = _a; interval = _interval; offSet = _offSet;
  }
  void display() { 
    noStroke();
    float fc = frameCount+offSet;
    float stage = fc % interval;
    float v = sin(stage/interval*PI);
    fill(0, 0, v*255);
    square(x,y,a);
  }
}

1 Like