Animate text opacity in a text String

Hi everyone. I have this class with a lot of cities. I want each city to have it’s opacity/alpha value be random and go between 0-255, kind of like a pulsing effect.

I’ve tried with if() statements but its not quite there

class OrdBillede2 {

  float opacity;

  color [] muligeFarver = {
    color(100, 214, 232), 
    color(22, 81, 32), 
    color(31, 66, 106), 
  };


  String [] words2 = loadStrings("byer2.txt");
  String [] individual;
  color [] byFarver;



  int o;
  PFont font1;
  float textStr2 = 15;


  OrdBillede2() {

    opacity = random(0, 255);


    font1 = loadFont ("Akkurat-Bold-18.vlw");
    textFont(font1);
    //for (int i = 0; i <10; i++) {
    //  words2 = concat(words2, words2);
    //}

    individual = split(join(words2, " "), " ");

    byFarver = new color[individual.length];



    for (int i = 0; i<individual.length; i++) {
      byFarver[i] = muligeFarver [int(random(muligeFarver.length))];
    } // loop
  } // OrdBillede2()


  void display() {


    showText (individual);
  } // void display
  void showText(String [] localArray) {

    int x = 80;
    int y = 176;

    for ( int i = 0; i <localArray.length; i++) {
      if (x+textWidth (localArray[i])>width-5) {
        x = 80;
        y += 30;
      }
      textAlign(CENTER);
      textFont(font1);
      textSize(textStr2);
      fill(byFarver[i], opacity);
      text(localArray[i], x, y);
      x+=textWidth (localArray[i])+22;
    }
    if (opacity > 255) {
      opacity = opacity-10;
    }
    if (opacity < 0) {
      opacity = opacity+10;
    }
  } // void showText
} // ordBillede2

For a pulsing effect you could try using a variable for the change in opacity in each update loop. And when the opacity reaches its bounds, negate that variable:

float opacity_change = 10;
float opacity = 10;

void showText(...) {
  // ...
  if (opacity <= 0 || opacity >= 255) {
    opacity_change *= -1;
  }
  
  opacity += opacity_change;
  opacity = clamp(opacity, 0, 255);
}
1 Like

Hi.

I’m getting the error message “the function clamp(float, int, int) does not exist.”

My apologies, I’m getting my syntax confused. I meant to type constrain(...).

:grin:

1 Like

works, thanks!

is it possible to make each city animate individually, so it’s more of a random pulsing rather than in unison?

edit: or from left -> right so it gets some sort of movement/rythm?

An alternative (and possibly simpler) pulsing animation could be done with sine functions and would give a more natural pulsing. I encourage you to try this as well:

float t = 0.1 * frameCount;
float phase = 0.0;
float opacity = map(sin(t + phase), -1, 1, 0, 255);

Explanation: We want opacity to pulse vary through time, so we use frameCount as it increases with time. Plug that into the sine function and we get output in the range of -1 to 1. Since opacity is in range of 0 to 255, we use map to linearly map -1 to 0 and 1 to 255.

For randomness in each of your cities, each city should hold an extra variable called phase (a random number between 0 and TWO_PI.

1 Like

For left->right movement, it’s very easy if you’re using sine waves, since you just need to have the phase variable increase from left to right.

Quick examples:

Random Phases:

float[] phases;

void setup() {
  size(600, 200);
  phases = new float[10];
  
  // random phases
  for (int i = 0; i < 10; i++) {
    phases[i] = random(0, TWO_PI);
  }
}

void draw() {
  background(0);
  
  for (int i = 0; i < 10; i++) {
    float opacity = map(sin(0.1 * frameCount + phases[i]), -1, 1, 0, 255);
    fill(255, opacity);
    
    ellipse(50 + i * 50, 100, 50, 50);
  }
}

randompulse

Linear (Left to Right) Pulse

The only thing I changed is the phases I defined at the start: You can change that i * -0.5 to change the speed and direction.

void setup() {
  size(600, 200);
  phases = new float[10];
  
  // linear phases
  for (int i = 0; i < 10; i++) {
    phases[i] = i * -0.5;
  }
}

linearpulse

2 Likes

Thank you very much.

Hi again FSXAC,

the effect works great, but it’s messing with my string now.

it’s repeating on the x-axis like this

instead of like this

class OrdBillede2 {

  color [] muligeFarver = {
    color(100, 214, 232), 
    color(22, 81, 32), 
    color(31, 66, 106), 
  };


  String [] words2 = loadStrings("byer2.txt");
  String [] individual;
  color [] byFarver;

  float [] phases;



  int o;
  PFont font1;
  float textStr2 = 15;


  OrdBillede2() {


    font1 = loadFont ("Akkurat-Bold-18.vlw");
    textFont(font1);
    //for (int i = 0; i <10; i++) {
    //  words2 = concat(words2, words2);
    //}
    phases = new float[10];

    for (int i = 0; i < 10; i ++) {
      phases[i]=random(0, TWO_PI);
    }

    individual = split(join(words2, " "), " ");

    byFarver = new color[individual.length];



    for (int i = 0; i<individual.length; i++) {
      byFarver[i] = muligeFarver [int(random(muligeFarver.length))];
    } // loop
  } // OrdBillede2()


  void display() {

    showText (individual);
  } // void display
  void showText(String [] localArray) {

    int x = 80;
    int y = 176;

    for ( int i = 0; i <localArray.length; i++) {
      if (x+textWidth (localArray[i])>width-5) {
        x = 80;
        y += 30;
      }

      for (int k = 0; k < 10; k++) {
        float opacity = map(sin(0.1*frameCount + phases[k]), -1, 1, 0, 255);
        textAlign(CENTER);
        textFont(font1);
        textSize(textStr2);
        fill(byFarver[i], opacity);
        text(localArray[i], x, y);
        x+=textWidth (localArray[i])+22;
      } // void showText
    } // ordBillede2
  }
}

Ah, the you’ve made ten different phases for each word you wanted to display. What I meant was having a phase per word. In this case, we can make a parallel list where the phases have the same size as your words array individuals.

Here’s what I would change:

  • In your constructor, instead of making a phases array the size of 10, we make it the same size as your individual array, so that for each item in individual, there is a phase for it.
float[] phases;

OrdBillede2() {
  // ...
  phases = new float[individual.length];

  for (int i = 0; i < individual.length; i ++) {
    phases[i]=random(0, TWO_PI);
  }
  // ...
}
  • Remove the nested for loop (the one with k) at the bottom of your showText function where it loops through all the phases for each word, instead just use the integer you already have: i to reference to phase for that letter.
void showText(...) {
  // ...

  for (int i = 0; i < localArray.length; i++) {
    // ...

    float opacity = map(sin(0.1*frameCount + phases[i]), -1, 1, 0, 255);
    textAlign(CENTER);
    textSize(textStr2);
    fill(byFarver[i], opacity);
    text(localArray[i], x, y);
    x+=textWidth (localArray[i])+22;
}

The result is that each word is no longer repeated 10 times:
wordpulse2

1 Like