How to make an ArrayList object "blink" without drawing the background

Hello. I have this code I can’t solve.

I’m using two arraylists that draw balls in a random location. The first one, “Bola” (= “Ball” in Portuguese), is random colored and placed on canvas with a timer. The second one, “Blink”, is one that would be “blinking” (changing the alpha value) every few frames in the same location of Ball. However, only every few blinks are appearing, but either white or transparent, not switching on or off.

I know that I could just put <background(0)> in the draw() function, but then I’d have to draw every single Bola or Blink in the same place every frame, since I want them to stay in that same random place. I don’t know how to do that, especially with the timer. Also, I will be projecting this with a “transparent background” on a poster for a uni project, so even if I’d used background, I wouldn’t know how to project only the balls.

If anyone could be kind enough to help I would be very grateful! Thanks, Mariana

Main code:

ArrayList<Bola> bolas = new ArrayList<Bola>();
ArrayList<Blink> blinks = new ArrayList<Blink>();

// for the timer
int lastTime; // tempo que já passou
int duration = int (random(500, 2500));

// location of balls and blinks
float rX, rY;

float lifespan;

void setup () {
  size(300, 300);

  lifespan = 255.0;

  // timer
  lastTime = millis();
}

void draw() {
  bolas.clear();
  blinks.clear();

  // bolas location
  rX = random(width);
  rY = random(height);

  // timer
  int elapsed = millis() - lastTime;

  // pelo tempo total
  if (elapsed > duration) {
    lastTime = millis();


    // adicionar bolas
    Bola b = new Bola(rX, rY);
    bolas.add(b);
  }

  for (int i = 0; i < bolas.size(); i++) {
    Bola b = bolas.get(i);
    b.display();

    Blink v = new Blink(rX, rY);
    blinks.add(v);

    //if (v.areDead()) {
      // blinks.remove(i-1);
      //println("dead");
    //}
  }

  for (Blink v : blinks) {
    v.display();
  }
}

The first class:

class Bola {

  ArrayList<PVector> bolas;
  float lx, ly;

  // change hue 
  float h = random(0, 360);

  Bola(float x, float y) {
    lx = x;
    ly = y;

    bolas = new ArrayList<PVector>();
    bolas.add(new PVector(x, y));
  }

  void display() {
    noStroke();
    fill(h, 90, 90);
    ellipse(lx, ly, 30, 30);

    println("ball displayed");
  }

  void add(float x, float y) {
    bolas.add(new PVector(x, y));
  }
}

The second class:

class Blink {
  float lx, ly;
  
  // to blink
  boolean on = true;

  ArrayList<PVector> blinks;

  Blink(float x, float y) {

    lx = x;
    ly = y;

    blinks = new ArrayList<PVector>();
    blinks.add(new PVector(x, y));
  }

  void add(float x, float y) {
    blinks.add(new PVector(x, y));
  }

  void display() {
    noStroke();
    //lifespan -= 1.0;

    if (frameCount%5 == 0) {
      if (on) {
        fill(255, 255);
      } else {
        fill(255, 0);
        on = !on;
      }
    }

    ellipse(lx, ly, 25, 25);

    println("add");
  }

  //is it still alive?
 // boolean areDead() {
    //if (lifespan < 0.0) {
      //return true;
    //} else {
      //return false;
    //}
  //}
}

PS.: I was also attempting a lifespan to “kill” the Blink object but I need to solve that first! :slight_smile: Thank you

Actually, this is the way to go.

When you use background() and draw everything every frame, it looks more crisp (better). Also, it is not time consuming for the processor.

See https://www.processing.org/reference/draw_.html

It is common to call background() near the beginning of the draw() loop to clear the contents of the window, as shown in the first example above. Since pixels drawn to the window are cumulative, omitting background() may result in unintended results.

Warm regards,

Chrisir

I dont understand exactly what you are trying to achieve however I spotted this in your code which is redundant.

if (frameCount%5 == 0) {
      if (on) {
        fill(255, 255);
      } else {
        fill(255, 0);
        on = !on;
      }
    }

you’re if statement says if(on){ doSomething()}else{on = false}

the else part is never true and therefore never runs.

Thank you! I got it from another question here in the forum. It’s there to make Blink “blink” from white to transparent every 5 frames. I’ll look into that. Thanks!

Thank you, Chrisir, for your answer. However, because each object is only being spawn in a specific time (using my timer) they aren’t re-drawn. That’s where my problem stands: if I use background(), they simply appear for only frame and disappear after background is drawn on top. I don’t know how to proceed from here.

Can I call and “store” those random locations each time the timer goes off so that the balls stay in place once they are spawned?

1 Like

Hi @marianalimoes

Let me see if I got it straight. So,

  1. You want a random Bola to appear on the screen
  2. That same bola should then blink every other N frames
  3. The Bola should be filled with one color and disappear without stroke when it blinks

Is this correct?
My questions are:

  1. should the blink effect take how much time or frames?
  2. the blink is from filled to transparent or from white to transparent?

Meanwhile I created this:

ArrayList<Bola> bolas = new ArrayList<Bola>();

// for the timer
int lastTime; // tempo que já passou
int duration = int (random(500, 2500));

// location of balls and blinks
float rX, rY;

float lifespan;

void setup () {
  size(300, 300);

  lifespan = 255.0;

  // timer
  lastTime = millis();
}

void draw() {
  background(255);
  // bolas location
  rX = random(width);
  rY = random(height);

  // timer
  int elapsed = millis() - lastTime;

  // pelo tempo total
  if (elapsed > duration) {
    lastTime = millis();


    // adicionar bolas
    Bola b = new Bola(rX, rY);
    bolas.add(b);
  }

  for (Bola b : bolas) {
      b.display();
  }

 
}


class Bola {

  ArrayList<PVector> bolas;
  float lx, ly;
  float angle = 0;

  // change hue 
  float h = random(0, 360);

  Bola(float x, float y) {
    lx = x;
    ly = y;
  
    bolas = new ArrayList<PVector>();
    bolas.add(new PVector(x, y));
  }

  void display() {
    noStroke();
    
   //Gradiente de cor usando função de seno
     angle += 0.02; // este valor é smooth
   // angle += 0.3; // este valor é mais rápido porque a frequência da onda é maior

    fill(h, 90, 90, 255*sin(angle)); //usa a função seno para o alfa variar entre 0 e 255. A rapidez é dada pelo valor incremental do angle
    ellipse(lx, ly, 30, 30);

    println("ball displayed");
  }

  void add(float x, float y) {
    bolas.add(new PVector(x, y));
  }
}

Best regards,
Miguel

3 Likes

Dear Miguel,
Muito obrigada!!

You got it all right. Thank you. I was trying out the noise() function first, then one flickering boolean and never thought of using sin(). By the way, why is it possible now to draw the bola in the same place, even with background()? I’m asking because before it wasn’t working for me.

I would like the blink effect to last 30 frames or so, but it could be adjusted after. Just to try out for now. I will try to solve that part, but any help is much appreciated! But yours was already more than I could have asked for. Regarding your second question, the blink could be either from filled to transparent. I was trying to put a white object on top for the blinking effect, but your way is much simpler.

I will look into this and post the final code (if I get it right) after, so it’s useful to someone else in the future. I will select your answer as the solution.

Thank you!

2 Likes

Alright, here’s Miguel’s code with a lifespan added to each Bola object. Thank you again, Miguel, and everyone that tried to answer!

Best regards,
Mariana

The code:

ArrayList<Bola> bolas = new ArrayList<Bola>();

// for the timer
int lastTime;
int duration = int (random(500, 2500));

// location of balls and blinks
float rX, rY;

float lifespan;

void setup () {
  size(300, 300);

  lifespan = 255.0;

  // timer
  lastTime = millis();
}

void draw() {
  background(255);
  // bolas location
  rX = random(width);
  rY = random(height);

  // timer
  int elapsed = millis() - lastTime;

  // pelo tempo total
  if (elapsed > duration) {
    lastTime = millis();


    // adicionar bolas
    Bola b = new Bola(rX, rY);
    bolas.add(b);
  }

  for (Bola b : bolas) {
    b.display();
  }
}

class Bola {

  ArrayList<PVector> bolas;
  float lx, ly;
  float angle = 0;

  // blink's duration
  float lifespan = 55.0;

  // change hue 
  float h = random(0, 360);

  Bola(float x, float y) {
    lx = x;
    ly = y;

    bolas = new ArrayList<PVector>();
    bolas.add(new PVector(x, y));
  }

  void display() {
    noStroke();

    // blink's duration
    lifespan--;

    //Alphas's gradient using the sin() function
    //Angle += 0.02; // smooth value
    angle += 0.6; // bigger frequency, more flickering

    //Uses the sin() to vary between 0 and 255
    //The speed is given by the incremental ue of the angle
    float a = 255*sin(angle);

    // if lifespan has ended
    if (finished()) {
      a = 255;
    }

    fill(h, 90, 90, a); 
    ellipse(lx, ly, 30, 30);

    println("ball displayed");
  }

  void add(float x, float y) {
    bolas.add(new PVector(x, y));
  }

  boolean finished() {

    if (lifespan < 0.0) { 
      return true;
    } else {
      return false;
    }
  }
}
2 Likes

Olá @marianalimoes,

Its possible to draw the bola in the same place even with background for two reasons:

  1. You are save the random position when you create the bola. So, when displaying it you will always have the same position
  2. when you use the background at each frame the screen is cleared and redrawn. So, initially, you have the screen white. Then, the first frame draws the bola with a given alpha. This completes the first loop. In the second loop, the background is cleared, and the alpha value of the bola increments according to the sin function. The bola is then drawn on the window. At this point the second loop has finished, but you’ll never see the background fully white, because in each loop iteration you clear the background but you also draw the bola in a new state. There is a small experiment that you can do: place the following code on your sketch
for (Bola b : bolas) {
     if(frameCount%10 == 0) b.display();
  }

What you will see is that the bola will only be displayed every 10 frames. So the other ones will have the background white (this will feel like the bola is blinking as well :D)
You can play with the value to appear as it is blinking more frequently or not

Best regards!
Bom trabalho :slight_smile: