Processing 101

Noisepages: Websites for smart artists.

Photo (CCBrian Brewer.

On its own, code is a painful way to draw. I remember being puzzled when learning LOGO on the Apple II as a kid. I was confused, and my drawings looked like crap. I didn’t know who this turtle was, or why it seemed to need explicit instructions to draw things that looked like nothing – or why my over-talented colleagues had made elaborate pictures of houses when I couldn’t seem to do anything. But I wasn’t pleased.

The answer, of course, was that simply drawing by coordinates isn’t any fun. It’s only when you can add variability to a drawing, and start to take advantage of the computer’s ability to form generative structures, that computers become useful, that they do something you can’t with a pen and paper. This entry and the next one will start to introduce the absolute basic elements that make that possible.

Reading: See chapter four of Dan Shiffman’s book Learning Processing for more detail on variables, and review chapter one for color.

Variable-ize it!

We usually talk about variables in respect to numbers. It’s fairly clear that the ability to change numeric values means that you can make interesting stuff happen. If instead of drawing a line between two static points, if you have a line that can be drawn to some variable point, you get motion and interaction and change and more interesting structures. That’s cool.

But if you’re not used to thinking in terms of variables, and you hate numbers, you may still not be sold. Let’s remember that words can be variable, too. Remember Mad Libs? You’d start with a phrase with blanks in it, like:

______ picked up the ________ and put it on his _______.

You can think of each blank as a variable. With a static value, this might not be terribly interesting. You might have “Peter picked up the hat and put it on his head.” But the power of Mad Libs was substituting variables for those values, yielding the more interesting “Peter picked up the gefilte fish and put it on his nose.”

The key with variables in Processing (and Java) is that you must first define the “space” in which the variable goes – the container – and then assign a value to that space. You can only define the space once, and each must have a unique name. But you can reassign values as many times as you like.

Let’s start with a simple example, using println(), the command for outputing text to the “console” – the black portion at the bottom of the Processing window in which Java and Processing can return errors and communicate messages back to you.

#1: Substitute a variable for a static element. Make things change.

Here’s how you might normally output text to the console:

println("Hello, world!");

The text is in quotation marks in order to define a String – a collection of characters. If you had used numbers, you might use something like this:

println(3);

Try each – nothing interesting there. To test outputing a variable in the same place, we can modify our code.

String hiThere = "Hello, World";
println(hiThere);

There are two steps:

1. Declare. First, we have to define a “container” – the space in the Mad Libs example. It needs a type and a name. “String” is the type and “hiThere” is the name.

2. Initialize. Next, we have to assign a value — at least once, or else the value of the variable will be “null.” as we’ll demonstrate in a moment.

Once those two steps are done, you can call upon the variable, as in the second line.

You can also define the container (which is called “declaring” the variable) separately from assigning the value (“initializing” the variable):

String hiThere;
hiThere = "Hello, world";
println(hiThere);

What you can’t do is to declare the variable twice:

String hiThere;
String hiThere = "Hello, world";

It’s okay if you don’t initialize the variable, but watch what happens:

String hiThere;
println(hiThere);

Pay attention to capitalization. Objects and special types called “composite” require capital letters. String is a composite of multiple characters – multiple letters and spaces and symbols, or “char” – so it gets a capital letter. The primitive number types below do not.

#2: Try numbers.

When working with numbers, you need to be specific about the type of the number. Generally speaking, this falls into whole numbers (“integers”) and numbers with decimal places (the most common being “floats”). (Even more precise than the floats are something called “longs,” but you won’t need them very often in Processing.)

int myWholeNumber = 3;
float myDecPoint = 3.2;

You can reassign values, so long as they’re assigned to the same type.

int myWholeNumber = 3;
int myOtherWholeNumber = 4;
myOtherWholeNumber = myWholeNumber;
println(myOtherWholeNumber);

You’ll see “4,” not “3,” because the whole point of variables is that you can change their value. Now, what you can’t do is to assign one type to another. Think of a specialized container that fits only one type. Literally, in the memory assigned on the computer, it’s the wrong size for a different type. (In Mad Libs, it’d be like having a space for “a kind of fruit” and instead using the value for “the name of your worst enemy.”)

Try this (it won’t work):

int myWholeNumber;
float myDecPoint = 3.2;
myWholeNumber = myDecPoint;

#3: Round numbers properly.

Okay, so we need to properly fit a square peg into a round hole here, by rounding it off.

Processing includes a function that converts from one type to the other:

float myDecPoint = 3.2;
int myRound = int(myDecPoint);
println(myRound);

Now, that looks right. But watch what happens if you substitute a higher number:

float myDecPoint = 3.7;
int myRound = int(myDecPoint);
println(myRound);

Instead of rounding, it truncates the number – it just drops everything after the decimal place. Side note: you may also see this written in Java as something like (int) myDecPoint.

Processing being Processing, though, you can probably guess what command you need in order to round something:

float myDecPoint = 3.7;
int myRound = round(myDecPoint);
println(myRound);

#4: Use color as a variable.

Now that we know how to use variables, let’s try seeing them in action, this time using color.

Processing defines how color is specified using a command called colorMode, which sets up either Red / Green / Blue (RGB) or Hue Saturation Brightness (HSB). I’ll put color theory in another post, but let’s have a look at color as a way of demonstrating how colors work.

For a review of RGB and HSB, see the online excerpt of Dan’s book on color:

http://www.processing.org/learning/tutorials/color/

Hold on tight – we’re going to introduce a number of useful commands at once!

void setup () {
size(400,400);
colorMode(RGB, 100);
}

void draw() {
}

void mousePressed() {
int myRed = round(random(0,100));
int myGreen = round(random(0,100));
int myBlue = round(random(0,100));
background(myRed,myGreen,myBlue);
println(myRed + ", " + myGreen + ", " + myBlue);
}

You already know that “draw” is called each frame. “mousePressed” is called when – and only when – a mouse button is pressed. Processing has a behind-the-scenes apparatus for listening to the mouse, and runs this function whenever it is needed.

random() is very cool – it outputs a random number each time it’s run. The output is within whatever range you specify. But this range is a float, so you do need to round it to use it as an integer.

Note that you can refer to colors as variable type “color,” but you can also simply call the color components “int”’s. (You can also use “char” when ranging from 0 to 255.)

So, we have an integer for red, green, and blue.

#5: Use Hue / Saturation / Brightness when RGB doesn’t make sense.

Thinking in red, green, and blue components is useful when you, say, want bright red. (255,0,0) is fire engine red. But it gets a little odder for other tasks. So, let’s hook up color the mouse, but use the more logical Hue, Saturation, and Brightness. Hue ranges across 360 degrees through the visible light spectrum – think Roy G. Biv, aka Red orange yellow Green Blue indigo violet.

void setup () {
size(400,400);
colorMode(HSB, 100);
} 

void draw() {
float howHigh = 1-mouseY/float(height);
int myHue = round(howHigh*100);
float howWide = mouseX/float(width);
int myBright = round(howWide*100);
background(myHue,100,myBright);
println(myHue);
println(howHigh);
}

#6: Use scoping properly.

There’s a problem witht the previous two examples, however. We’re declaring a new variable each frame, which turns out to be not the best form – and certainly counts as overkill.

Now, I find most beginning users are tempted to do something like this:

void setup () {
size(400,400);
colorMode(HSB, 100);
int myHue = 0;

void draw() {
myHue = myHue + 1;
background(myHue,100,100);
println(myHue);
}

That makes sense, right – or so you’d think? “Setup” runs once, and “draw” runs every frame. “Setup” is where you, you know, set stuff up.

Run it, though, and it doesn’t work. If you examine the error message, you’ll see Processing isn’t finding the variable you just created. The reason is something known as “variable scope.”

In a lot of code examples, you’ll see many variable names are pretty generic, like “myNum.” Even something more specific, like “circleWidth,” is something that might get used more than once. Imagine you’re collaborating with another programmer. You used “circleWidth” as a variable name in your code to draw bubbles on the screen. She used “circleWidth” to draw the sun. Now, if your code assumes one “circleWidth” is the same as another, the drawBubbles() code will wind up using the width of the sun from your friend’s drawSun(), and… well, you get the idea.

The solution is for Java (and thus Processing) to limit the “scope” of variable names to the method from which they’re called.

In Processing, the solution is simple: declare variables that you want used throughout the sketch at the top, outside of setup, draw, mousePressed, and any other functions you’ve created. You can still initialize the variable inside setup if you like, or simply initialize it at the declaration, as in my example:

color myHue = 0;

void setup () {
size(400,400);
colorMode(HSB, 100);
frameRate(15);
}

void draw() {
if(myHue < 100) {
myHue += 1;
} else {
myHue = 0;
}
background(myHue,100,100);
println(myHue);
}

void mousePressed() {
myHue = 0;
}

This example also demonstrates why all of this is useful in practice. Here, we’re able to increment through hue levels using the draw loop, and do it with a logical number range (0 to 100).

Stay tuned for more on working with variables, particularly with the awesome map() command in Processing.

2 Responses

  1. Mac

    Thanks for another informative post!  I’ve messed around with Processing, but this blog has already led me to a number of  “so that’s how that works!” moments.   Are you planning on covering classes and objects at some point?

  2. Peter Kirn

    Absolutely covering methods (“functions”) and classes.

Leave a Reply