Changing colour of shapes over time

edited November 2017 in Library Questions

Hi everyone,

Now I'm very rusty with processing so I'm 100% sure I'm making some dumb mistakes here.

I'm trying to make the ellipses in this sketch change colour as they become older but I can't figure it out for the life of me!

Thanks in advance for any help/suggestions :)

See code here:

import ddf.minim.*;

Minim minim;
AudioInput in;
 float volume = 0;
float volumeF = 0;

   int maxParticles=1000; // max number of particles. real particles count depends on ppf and its lifetime
int addPPF=2;         // number of particles per frame added
ArrayList particles;

void setup(){
  size(900,900, P3D);
  frameRate(30);
  smooth();
  background(0);
  noStroke();
     minim = new Minim(this);
  minim.debugOn();

  // get a line in from Minim, default bit depth is 16
  in = minim.getLineIn(Minim.MONO, 512);


  particles = new ArrayList();
}

void draw(){
  background(0); // overpaint circles the frame before
  //  for(int i = 0; i < 1; i++)
  //{
     volumeF = in.right.level()*1000;
  volume = 0.8*volume + 0.2*volumeF;
  if(particles.size()<maxParticles){
    // add particle(s)
    for(int k=1; k<= volume; k++){
      particles.add(new Particles());
    }
  }
  //}

  // run trought all Balls and make some action
  for(int j=0; j<particles.size(); j++){
    Particles particle = (Particles)particles.get(j);
    // if particle still alive
    if( particle.alive() ){
      // update x/y positions
      particle.position();
      // now draw as cirle
      if( particle.lt < 200 ) fill(20, 20, 20, particle.lt);
      else if(particle.lt >= 200) fill(50, 50, 50, particle.lt);
      else if(particle.lt >= 300) fill(100, 100, 100, particle.lt);
      else if(particle.lt >= 400) fill(150, 150, 150, particle.lt);
      else if(particle.lt >= 500) fill(200, 200, 200, particle.lt);
      else if(particle.lt >= 600) fill(250, 250, 250, particle.lt);
      //stroke(random(100));
      ellipse(particle.x, particle.y, particle.r, particle.r);

  }else{
      // if lifetime is running out, delete
      particles.remove(j);
    }
  }
}


  void stop()
{
  // always close Minim audio classes when you are done with them
  in.close();
  minim.stop();

  super.stop();
}

public class Particles {
  float r, x, y, _x, _y, dx=0, dy=0, lt;

  // init start-values
  public Particles() {
    // start position center
    x=width/2;
    y=height/2;
    // now random values to make it non-linear
    lt=random(5,2000);       // lifetime in frames
    r=random(1, 4);        // circle Radius
    _x=random(-0.001, 0.001);    // stepwidth in x-pos (left, right)
    _y=random(-0.001, 0.001);    // stepwidth in y-pos (up, down)
  }

  public void position() {
    // stepwidth increases, circlespeed is exponential
    dx+=_x;
    dy+=_y;
    x+=dx;
    y+=dy;
  }

  public boolean alive(){
     if(lt<=0){ return false; }else{ lt--; return true; }
  }
}

Answers

  • (the forum has trouble with /* */ style quotes. use // single line comments where possible)

    (ctrl-t in the processing editor will indent your code nicely)

  • edited November 2017

    lerpColor() is your new friend. Have a start color, c, and a finish color, k, each of which you assign to a random color initially. Also have a float lerpAmt that is how much lerping(?) lerpColor() should do - initially zero. And have float lerpAmtChange that is a small amount that lerpAmt should have added to it each frame (like 0.01).

    Then the color you want is

    fill( lerpColor( c, k, lerpAmt ) );
    

    And the next steps should be:

    lerpAmt += lerpAmtChange;
    if( lerpAmt >= 1 ){
      c = k;
      k = <random color>;
      lerpAmt = 0;
      // Optional: lerpAmtChange = <new random value>;
    }
    
  • Hey @TfGuy44 , thanks for the response :)

    That sounds like exactly what I need!

    I'm confused as to whereabouts in the code I need to put the if statement though?

  •   if( particle.lt < 200 ) fill(20, 20, 20, particle.lt);
      else if(particle.lt >= 200) fill(50, 50, 50, particle.lt);
      else if(particle.lt >= 300) fill(100, 100, 100, particle.lt);
      else if(particle.lt >= 400) fill(150, 150, 150, particle.lt);
      else if(particle.lt >= 500) fill(200, 200, 200, particle.lt);
      else if(particle.lt >= 600) fill(250, 250, 250, particle.lt);
    

    if the lt value is 450, say, they the 2nd, 3rd and 4th conditions here will be true but only the second will be applied. in fact anything over 200 will run ONLY that condition because of the elses.

  • @koogs thanks for the response - I was being pretty careless there!

    Shall I remove the elses? Or can i just change the numbers?

  • @TfGuy44 - I worked it out! Unfortunately, though it's not quite what I had in mind.

    I would like the ellipses in the centre to be a different colour to the ones on the outside, so the 'older' they are, the brighter/redder they are (or something along those lines...

    Does that make sense?

    I feel like I was almost there with the series of else if statements (i had multiple colours simultaneously) but my maths was just wrong in the counting perhaps??

  • Ah, okay. Yeah, a bunch of if-else statements would be good for a fixed number of colors. But if you want to have the color depend on some other factor, like age, then you should use the map() function to convert one range of values (the age) to another range of values (colors).

    Here's some example code:

    float hue;
    
    void setup(){
      size(800,200);
      colorMode(HSB,255);
      hue = random(255);
    }
    
    void draw(){
      background(0);
      fill( hue, 255-map(mouseX,0,width,0,255), 255);
      ellipse(mouseX, 50, 20, 20);
      fill( (hue + map(mouseX,0,width,0,128))%255, 255, 255);
      ellipse(mouseX, 100, 20, 20);
      fill( hue, 255, 255-map(mouseX,0,width,0,255) );
      ellipse(mouseX, 150, 20, 20);
    }
    
    void mousePressed(){
      hue = random(255);
    }
    
  • You could switch the order of the checks, so that it checks for higher numbers first.

    Or change the >s for <s, that way it'll only match one thing.

    Or, yes, remove the elses. Less efficient because you'll set the variable multiple times but...

    (All untested)

  • lerpColor (singular) is a great processing built-in for mapping between two colors over time, but if you are trying to map between multiple colors over time (like a temperature map, e.g. red-white-blue) then you should check related discussion of writing a custom lerpColors (plural) function:

    - https://forum.processing.org/two/discussion/comment/92946/#Comment_92946

Sign In or Register to comment.