# Time-Based Animation

We can make the sketch animate by using time as an input. Modify `y` so that it is a function of time (`millis()`). This causes the sketch to animate.

``````void setup() {
size(600, 600);
}

void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
float y = map(sin(i + millis() / 100), -1, 1, 80, 120);
circle(x, y, 20);
}
}``````

Remember that the mathematical sin() function has an output range between -1.0 and 1.0, so we need to map it to some larger value range for the y’s so that we can see circles move. Thus, we use the `map()` function.

Note: Now that the circles are drawn in a different position each time `draw()` is called, it is important to clear the canvas (`background(100)`) at the beginning of `draw()`. Otherwise each circle will be drawn on top of all the circles drawn by previous calls to `draw()`. In all the sketches so far we have drawn the background once in `setup()`, and since all the circles were drawn at the same position, this was not detectable. Now, we have moved the call to `background()` into `draw()`.

Try this: Change the sketch to animate the size of the object, instead of its position. You can base your work on this sketch and a one in XXX.

# Random

The previous sketch uses time to drive one of the shape’s properties (its vertical position). Let’s use `random()` instead.

``````void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
float y = random(80, 120);
circle(x, y, 20);
}
noLoop();
}``````

Note: There are three screenshots next to the code, to show that the `random()` returns a different sequence of values, and therefore the sketch draws a different image, each time it is run.

The `noLoop()` function prevents `draw()` from being called more than once. Let’s see what would happen if we removed it.

``````void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
float y = random(80, 120);
circle(x, y, 20);
}

}``````

Aargh! Just as the previous sketch drew the circles at different positions each time it was run, this one draws them at different positions every frame.

What if we want to remember the position from frame to frame, so that we can draw the circles at the same position each time (or, move them in a more organized way that incorporates their previous position)?

In Processing, the way to remember things is to use a variable. A variable can hold a single value, but we want to remember several values: the vertical position of each circle. The trick is that the single value that the variables holds can be an array, which itself holds several values. Here’s what it looks like to use an array to hold the y values, inside `draw()`.

``````void draw() {
background(100);

float ys[] = new float[20];

for (int i = 0; i < 20; i++) {
ys[i] = random(80, 120);
}

for (int i = 0; i < 20; i++) {
int x = 10 + 50 * i;
circle(x, ys[i], 20);
}
}``````

Note: Processing needs to know how many elements are in the array when it is created, thus we need to say `new float[20]`, however there are ways to change the length of the array later if needed.

As you can see above, simply using an array as intermediary doesn’t help with the jitter if the array is still initialized on each call to `draw()`. Each call to `draw()` makes a new array, stores it in a new variable named `ys`, and fills the array with a new set of random numbers.

To get a stable array that can be seen from all the calls to `draw()` make the array a global variable, and initialize it in `setup()` instead of `draw()`.

``````float ys[] = new float[20];

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

for (int i = 0; i < 20; i++) {
ys[i] = random(80, 120);
}
}

void draw() {
background(100);

for (int i = 0; i < 20; i++) {
int x = 10 + 50 * i;
circle(x, ys[i], 20);
}
}``````

Now we can combine this with time-based animation, to get an effect that uses both randomness (from `random()` in `setup()`) and time (from `millis()` in `draw()`), without getting new random numbers every frame.

``````void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
float size = map(sin(i + millis() / 100), -1, 1, 10, 20);
circle(x, ys[i], size);
}
}``````

# Update-Based (or Implicit) Animation

An alternative to time-based animation is to modify (or update) some values each time `draw()` is called.

The previous sketch initializes an array with random values, and then combines the values that it reads from this array with an expression that uses time. This sketch doesn’t use time at all; instead it writes to the array as well, so that the next frame can pick up where this frame left off.

``````float ys[] = new float[20];

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

for (int i = 0; i < 20; i++) {
ys[i] = random(80, 120);
}
}

void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
circle(x, ys[i], 20);
ys[i] += random(1);
}
}``````

# Noise

Randomness is good for organic or interesting patterns. Continuity and stability are necessary for smooth, pleasant animation. Storing the random values in an array is one way to combine randomness with continuity.

Another is to use the `noise()` function. Like `random()`, `noise()` returns values that don’t seem to have much to do with each other, at least when its arguments are far apart (as they are in the next sketch). Unlike `random()`, `noise()` returns the same values each time you call it with the same arguments.

Here’s the sketch from the Random section above, with `random()` replaced by `noise()`. Unlike the first sketch in Random, we don’t need `noLoop()` to keep the drawing from flickering: since for each circle `noise()` is called with the same input (`i`), its value is the same, and `draw()` draws the same thing from frame to frame.

``````void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
float y = map(noise(i), 0, 1, 80, 120);
circle(x, y, 20);
}
}``````

Note: `noise()` returns a value between 0 and 1, like `random()` with no arguments. To make it behave like `random(80, 120)`, we must use `map()` or write our own version of this arithmetic.

`noise()` can take up to three values. We have used one: the index of the circle within the line of circles. Add a second argument to `noise()`, so that its output is based on the time, as well as on the circle’s index (`i`).

Fun Note: The `noise()`function’s algorithm for making organic, useful, coherent noise was invented by NYU Prof. Ken Perlin in 1983 to introduce nature-like effects such as fire and water into what had been a more machine-like appearance of computer graphics at the time. He was awarded an Oscar(tm) for this achievement for the movies, and as he says in the linked article, his “Mom was very happy”. You can read more here. Perlin noise has been used in almost every CGI film made, and it is also now the staple form of noise supplied in programming language primitives such as in Processing.

``````void draw() {
background(100);

for (int i = 0; i < 20; i++) {
float x = 10 + 50 * i;
float y = map(noise(i, millis() / 1000.0), 0, 1, 80, 120);
circle(x, y, 20);
}
}``````

Note that we need to use `1000.0` again, instead of 1000, to keep smoothness from decimal (float) numbers. `noise()` returns values that are close together when its inputs are close together. (It is kind of like a cross between `random()` and `sine()`. ) The successive values for `i` from item to item are far apart, so there’s not any continuity between the first and the second element. The successive values of `millis() / 1000` are close together from one call to `draw()` to the next so there is continuity from frame to frame, resulting in a smooth animation. (This is why we divide `millis()` by 1000.0 The value of `millis()` itself changes too much from one frame to the next; this is how we slow it down.)

# Theory: Sources of change

In order to draw a different image each frame, `draw()` needs access to something that has a different value each time `draw()` is called. Here are some possibilities:

• Time. In p5.js, the `frameCount` function and the `millis()` variable are the sources of time. We explored that in Time-Based Animation.
• A global variable. You can define your own variable that has global scope (is defined outside of `setup()` and `draw()`), and use it to remember changes from one frame to the next. There was an example of this in Update-Based Animation.
• Randomness. The `random()` function returns a different number each time you use it. This will a frame that calls `random()` to draw differently each frame. There were an examples of this in Random and Noise.
• Computer peripherals. Input devices that are connected to or built into the computer include the mouse, keyboard, webcam, and microphone.
• Other connections to the outside world. These can come from an Arduino or other device connected on the USB serial port, or from the internet.