In these notes you will learn:
So far, all the animations we’ve created move an object by changing its position. In this note we will see another kind of animation: fading. When the user clicks on the screen a big blue circle appears. It then begins to fade away until it is invisible.
The first step in writing any program is to decide exactly what it should do. Since we are writing a demonstration of a new kind of animation, we want to keep it relatively simple. So lets agree that the program works as follows: when the user clicks on the screen, a circle appears at the click-point and then fades away to invisibility.
We’ll need variables to store its (x, y) center. The circle won’t be moving or changing shape, so we don’t need dx, dy, or diam.
How do we get the circle to fade? Fading means that the circle starts out with some totally opaque (i.e. not see-through) color, and then slowly becomes more transparent, finally disappearing completely.
Recall that Processing lets you specify a colors alpha value, which sets the transparency of a color. Alpha values in Processing range from 0 to 255, where 0 is totally transparent (i.e. invisible), and 255 is totally opaque (i.e. not transparent at all).
So we will implement fading by slowly decreasing the alpha value of the circle’s fill color.
Lets write a program that displays a big blue circle wherever the user clicks with the mouse. There is no fading yet; we’ll add that next after we get this working:
float x;
float y;
void setup() {
size(500, 500);
smooth();
}
void draw() {
background(255);
noStroke();
fill(0, 0, 255);
ellipse(x, y, 150, 150);
}
void mousePressed() {
x = mouseX;
y = mouseY;
}
Recall that the mousePressed() function is automatically called by Processing whenever the user clicks a mouse button. When it’s called here, it sets x and y to be the position of the mouse, and so when draw() is called the circle will be drawn centered at the most recent mouse-click.
Now lets add the fading effect. We’ll need a variable to keep track of the current transparency:
float transparency; // ranges from 0 to 1 (0 = totally transparent)
Lets agree that transparency ranges from 0 (totally transparent) to 1 (totally opaque). A range of 0 to 1 is pretty common because it makes it easy to talk about percentages, e.g. 0.73 is exactly 73% of the way between 0 and 1.
We will also need a variable that tells us how much to decrease the transparency on each call to draw(). In other words, we need a variable that stores how fast the transparency change:
float dtrans;
We call this variable dtrans following the convention of starting “speed” variables (like dx and dy) with the letter d.
Now we can add the fading effect. We need to make only a few changes:
Whenever the user clicks the mouse, the circle is drawn at a new location with a totally opaque transparency. Thus we need to set transparency to 1 at the end of mouseClick():
void mousePressed() {
x = mouseX;
y = mouseY;
transparency = 1;
}
Whenever the circle is drawn, its fill color must be drawn taking the transparency into account. This is not completely straightforward. For instance, this doesn’t work:
void draw() {
background(255);
noStroke();
fill(0, 0, 255, transparency); // wrong!
ellipse(x, y, 150, 150);
}
The problem is that the fill function expects a value in the range 0 to 255 (you learn this by reading the fill() function documentation). But transparency ranges from 0 to 1.
We could, of course, change our previous decision and let transparency range from 0 to 255. That would be fine for this one program. But in general, it’s probably not a good idea. In large programs, you may have many different ranges, and if these ranges all have different begin and end points you will soon find it takes a lot off mental effort to keep track of them. It’s simpler if you require that all ranges start at 0 and end at 1.
So lets keep the range of transparency as it is, and instead use the map function to convert transparency into a corresponding value in the range 0 to 255:
void draw() {
background(255);
noStroke();
float a = map(transparency, 0, 1, 0, 255);
fill(0, 0, 255, a);
ellipse(x, y, 150, 150);
}
This works! The expression map(transparency, 0, 1, 0, 255) returns the a number in the range 0 to 255 that corresponds to the same value of transparency from 0 to 1.
After the circle is drawn, we need to change transparency by adding dtrans to it:
void draw() {
background(255);
noStroke();
float a = map(transparency, 0, 1, 0, 255);
fill(0, 0, 255, a);
ellipse(x, y, 150, 150);
transparency += dtrans;
}
Since we’ve decided to add dtrans to transparency (instead of subtracting it), we must remember to initialize dtrans to a negative value in order to get a fading effect.
An important detail arises here. We’ve decided that transparency ranges from 0 to 1, but the statement transparency += dtrans does not respect that range. For instance, if dtrans is negative, then if you add dtrans enough times transparency will become negative, i.e. it will be outside of the agreed-upon range of 0 to 1.
Sometimes this might not matter. In fact, in this program, it doesn’t matter because it turns out that if you call fill with a negative alpha value then the alpha is treated as if it were 0.
But in general it is unwise to rely on functions handling errors the way you want. So we should make sure that the value of transparency is always in the correct range. The easiest way to do that in Processing is to use the constrain function:
void draw() {
background(255);
noStroke();
float a = map(transparency, 0, 1, 0, 255);
fill(0, 0, 255, a);
ellipse(x, y, 150, 150);
transparency += dtrans;
transparency = constrain(transparency, 0, 1);
}
The expression constrain(transparency, 0, 1) always returns a value from 0 to 1. If transparency happens to be between 0 and 1, then it’s value is returned. Otherwise, if transparency is less than 0, 0 is returned; if transparency is greater than 1, 1 is returned.
In fact, it is not hard to write your own version constrain:
float myConstrain(float x, float lo, float hi) {
if (x < lo) {
return lo;
} else if (x > hi) {
return hi;
} else {
return x;
}
}
float x;
float y;
float transparency; // 0 <= transparency <= 1
float dtrans; // the change in transparency on each call to draw
void setup() {
size(500, 500);
dtrans = -0.01;
smooth();
}
void draw() {
background(255);
noStroke();
float a = map(transparency, 0, 1, 0, 255);
fill(0, 0, 255, a);
ellipse(x, y, 150, 150);
transparency += dtrans;
transparency = constrain(transparency, 0, 1);
}
void mousePressed() {
x = mouseX;
y = mouseY;
transparency = 1;
}