PFA:002 – Animating With Code

Inspiration

Today’s Artists

  • Casey Reas – One of the original creators of Processing

Making Things Move

So far we have been creating programs that run only once. In order to create animations or interactive software, we need to somehow make the program run continuously. Fortunately, Processing makes this pretty easy. It has built in functions called setup() and draw(). The setup() function runs once when the program starts and the draw() function keeps running on a loop until you quit the program. This is how you use them:

void setup() {
}

void draw() {
}

Now we have the functions in place, but they don’t actually do anything yet, since there is no code inside the functions. Anything that is between the curly braces { } after setup, is part of the setup function. Same thing applies for the draw function.

Also remember to write the word void in front of the setup and draw. We will come back to why that needs to be there later, but for now, you just need to remember that it should always be there. From now on, we should always start any program we write by first adding these two functions. The next step is to add some code inside the functions.

void setup() {
 // Set the size of the window
 // This needs to be only done once
 size(400, 400);
}

void draw() {
 // draw an ellipse
 ellipse(200, 200, 40, 40);
}

It looks like nothing special is going on. There’s just an ellipse in the middle of the window. It looks like a still image, but actually the program is drawing the ellipse over and over 60 times a second. It’s just always in the same place. Let’s edit the code and make the ellipse move.

We can replace the numbers with special variables called mouseX and mouseY, they are built-in variables in Processing that allow you to use the mouse coordinates. With the code below, you should be able to move the ellipse around using you mouse cursor.

void setup() {
 // Set the size of the window
 // This needs to be only done once
 size(400, 400);
 background(134,82,132);
}

void draw() {
 // draw an ellipse where the mouse cursor is
 ellipse(mouseX, mouseY, 40, 40);
}

This is what you should see as a result:

You might be wondering, why do you get that trail of ellipses drawing on top of each other instead of just one of them? That is because Processing does not automatically clear the window on each frame, and we are only drawing the background once in the setup. Watch what happens if we move the background() command inside the draw function.

void setup() {
 // Set the size of the window
 // This needs to be only done once
 size(400, 400);
}

void draw() {
// clear the bacgkround on each frame
 background(134,82,132); 
 // draw an ellipse where the mouse cursor is
 ellipse(mouseX, mouseY, 40, 40);
}

Variables?

Before we go any further. Let’s introduce one very important concept about programming. Variables.

As you can see, writing code involves a lot of numbers and very often you will use the same value in many places. Let’s create a new Sketch and draw a bunch of ellipses that are all the same size.

void setup(){
  size(400,400);
  background(0);
}

void draw(){
  fill(255);
  noStroke();

  ellipse(100,200,20,20);
  ellipse(200,200,20,20);
  ellipse(300,200,20,20);
}

If we would like to change the size of these ellipses we would need to go and change the parameters on each of them. Not a huge deal when you only have three ellipses, but once you get to some more complicated programs and start dynamically changing some of the parameters, it’s going to be really important to know how to use variables. (Sidenote: There are also much better ways to draw multiple ellipses than writing them line by line. We will look at those ways later in the form of the for loop)

Variables can be thought of as boxes that can contain certain amount of certain type of data. You put the data inside the box and you can then access that data in that box at a later stage in your code. So let’s see how we could use them here.

First of all, you need to declare the variable. Declaring means that you give your variable a name (can be almost anything). You often also assign some value to the variable. Basically you create a box, write a name on the side of it and put some stuff inside the box. Here we declare a variable called eSize and assign it a value of 30.

int eSize = 30;

Ok, that makes sense, but what is that ‘int’ doing there? Int means integer (a number without decimals). Variables have specific data types and int is one of them. This variable, or box, can only store certain type of data. Because it has been declared as an int, it cannot store other types of data such as text (String) or numbers that have decimal values (float).

Variables also have a scope, the area of the code where the variable is visible/usable. The eSize has been declared before both of the functions (setup and draw) so it is a global variable. It can be accessed and modified in any other part of the code. We will talk about the scope of variables in more detail later.

Let’s use the variable in our code.

int eSize = 30;

void setup(){
  size(400,400);
  background(0);
}

void draw(){
  fill(255);
  noStroke();

  ellipse(100,200,eSize,eSize);
  ellipse(200,200,eSize,eSize);
  ellipse(300,200,eSize,eSize);
}

Now that the size is a variable, we can easily change the size of all ellipses just by changing the value on one line of code. But laziness is not the only reason variables are used, they are also essential when we need to store and modify values.

Modifying the Values of Variables

In order to move and animate the graphical objects with code, we need to modify the values of our variables while the code is running. We already kind of did it by using the mouse coordinates, but let’s take a look at something that does not rely on interacting with the mouse.

float eSize = 100;

void setup(){
  size(500,500);
  frameRate(60);
  background(255);
  println("Setup done!");
}

void draw(){
  //background(255);
  fill(130,40,50);
  ellipse(mouseX,mouseY,eSize,eSize);
  eSize = eSize + 1;
  println("Ellipse size: " + eSize);
}

The ellipse keeps on growing, because each frame we add one to the previous value of the eSize variable. Try changing the framerate to slow down or speed up the program to see this more clearly. Also try other math operations instead of addition (+). You could subtract (-), divide (/) or multiply(*).

We are also using the command println() to print out the value stored in the eSize variable. Printing values is a very important debugging tool. It helps you to understand how your variables are changing while the code runs. It is also very useful for printing information about various stages of the program. Here we print out the text “Setup done!” when the code finishes the Setup part of the code.

Another new thing that we do here is that we are using float instead of int as the data type of our variable. The operations you do for your variables often result in values that have decimal values. Int does not support decimal values and you would get errors in your code. Therefore, we use the float. Floats use more memory, but you don’t usually have to worry about that with software running on your computer. You probably have plenty of memory. From now on, we should use float as the data type for most of our numerical values in Processing. (Note: Once we start working with the Arduino, we need to be a lot more careful about avoiding floats).

We will look at more advanced examples related to modifying variables during the next lesson. Let’s finish today off with something a bit more fun.

Random

A very simple trick that creates very interesting effects is to use random(). Anywhere that you have a static number in your code, you could try replacing it with a random number. You need to define one or two parameters inside the random:

  • One value: random(100) – This will generate random numbers between 0 and 100. You are only defining the max value.
  • Two values: random(50,100) – This example will generate random values between 50 and 100. You are defining the min and max values.

You could easily create something like this:

…or this:

… or this:

2nd Assignment

This is one of the mandatory assignments that you need to complete to pass this class.

  • Use the random() funtion and the 2D shapes to draw some interesting patterns.
  • Try using the random on different things: size, position, color etc.
  • Add your code to our OpenProcessing classroom. Alternatively, send the code to me via email or Slack.