The setup and draw methods are methods with specific meaning in Processing: setup is called when the window is created, while draw is called whenever the window is redrawn, which is a lot. To get an idea of how often the window is redrawn, let’s write a simple Processing sketch in which the draw method simply sets the background to a random color. We can set the color of the window’s background by calling the background method. The background method takes three arguments, indicating the amount of red, green, and blue we want in the color of the window’s background. The amount of each color can be anything from 0 to 255. For example, the statement background(255,0,0) tells Processing to draw a red background.
To make the background color random, we can put random(0,255) in for each of the three colors. When random is called, it generates a random number and returns the number that it generated. When a method returns a number, we can a call to that method in any spot in our code that we would normally put a number. Instead of calling background with actual literal numbers like this: background(255,0,0), we can replace the 255 and each of the 0’s with random(0,255) like so:
background(random(0,255), random(0,255), random(0,255))
This will generate a completely random background. Figure 1.1 shows the code. You can run the program by pressing Start in Figure 1.1. As you can see when this code is run, draw gets called a lot.
void setup() { size(800,400); } // end setup() void draw() { background(random(255),random(255),random(255)); } // end draw()
WARNING: The frame rate has been slowed way down to make sure the repeated flashing of the background doesn’t bother anyone. However, even with the frame rate slowed down, if you are sensitive to weird, flashing light shows, you may not want to look at this animation. and you certainly don’t want to run the code above in your own application without the frame rate adjusted. The Pause button will stop the animation.
We are almost ready to get our Monster to move. Before we get involved with the complications of tracking the mouse position, though, let’s see if we can get the Monster to appear at a random rather than fixed position in the window every time the window is redrawn.
Figure 1.3 shows our original code split into the setup and draw methods.
void setup() { size(800, 400); } // end setup() void draw() { ellipse(100, 125, 50, 50); line(100, 125, 100, 135); ellipse(90, 125, 5, 5); ellipse(110, 125, 5, 5); rect(90, 140, 5, 6); rect(97, 140, 5, 6); rect(104, 140, 5, 6); } // end draw()
First, let’s set up the outer ellipse to appear at a random distance from the left side of the window. This can be done by replacing the first argument in the first call to ellipse with a call to random as shown in Figure 1.4.
void setup() { size(800, 400); } // end setup void draw() { ellipse(random(20, 600), 125, 50, 50); line(100, 125, 100, 135); ellipse(90, 125, 5, 5); ellipse(110, 125, 5, 5); rect(90, 140, 5, 6); rect(97, 140, 5, 6); rect(104, 140, 5, 6); } // end draw()
Run the animation in Figure 1.5 to see how this displays.
It really isn’t quite what we expected, is it? Remember that draw is called like 60 times a second to redraw the window. The way draw works in Processing, however, is that whatever you tell Processing to draw will be drawn on top of what is already there. In other words, Processing remembers everything you drew before, redraws it on the window, and then on top of that, draws whatever new stuff you tell Processing to draw in the draw method. If you want to erase what was in the window before, you must first call the background method, which you can think of as redrawing the background on top of whatever was there before.
Figure 1.6 shows the code above modified to draw a background each time the window is redrawn. The resulting animation is in Figure 1.7.
void setup() { size(800, 400); } // end setup void draw() { background(127,120,200); ellipse(random(20, 600), 125, 50, 50); line(100, 125, 100, 135); ellipse(90, 125, 5, 5); ellipse(110, 125, 5, 5); rect(90, 140, 5, 6); rect(97, 140, 5, 6); rect(104, 140, 5, 6); } // end draw()
It looks like we made some progress, but it would be nice if the whole face moved rather than just the outer ellipse. Let’s change the code to move the entire face around randomly by putting a call to random in for each of the positional arguments. The values of the arguments need to be slightly offset sometimes to keep the relationship to the center of the face. Figure 1.8 shows the code and Figure 1.9 shows the animation.
void setup() { size(800, 400); frameRate(1); } // end setup void draw() { background(127,120,200); ellipse(random(0, 800), random(0,400), 50, 50); line(random(0, 800), random(0,400), random(20, 600), 135); ellipse(random(0, 800)-10, random(0,400), 5, 5); ellipse(random(0, 800)+10, random(0,400), 5, 5); rect(random(0, 800)-10, random(0,400)+15, 5, 6); rect(random(0, 800)-3, random(0,400)+15, 5, 6); rect(random(0, 800)+4, random(0,400)+15, 5, 6); } // end draw()
That was not what we were looking for. When we call random, we get a random number. When we call random again, we get a different random number. But if we want the nose to be in the center of the face, the center of the outer ellipse and the beginning of the line for the nose need to be drawn at the same position. The code we have does not do that because it gets a new random position for each part of the face. To keep the Monster together as it randomly moves around the window, we need to learn something new. We need to learn to define attributes.