7

Functions

When it’s all mixed up, better break it down.

—Tears for Fears

In this chapter:

 Modularity

 Declaring and defining a function

 Calling a function

 Arguments and parameters

 Returning a value

 Reusability

7-1 Break it down

The examples provided in Chapter 1 through Chapter 6 are short. I probably have not shown a sketch with more than 100 lines of code. These programs are the equivalent of writing the opening paragraph of this chapter, as opposed to the whole chapter itself.

Processing is great because you can make interesting visual sketches with small amounts of code. But as you move forward to looking at more complex projects, such as network applications or image processing programs, you will start to have hundreds of lines of code. You will be writing essays, not paragraphs. And these large amounts of code can prove to be unwieldy inside of your two main blocks — setup() and draw().

Functions are a means of taking the parts of a program and separating them out into modular pieces, making code easier to read, as well as to revise. Let’s consider the video game Space Invaders. The steps for draw() might look something like:

 Erase background.

 Draw spaceship.

 Draw enemies.

 Move spaceship according to user keyboard interaction.

 Move enemies.

What’s in a name?

Functions are often called other things, such as “procedures” or “methods” or “subroutines.” In some programming languages, there is a distinction between a procedure (performs a task) and a function (calculates a value). In this chapter, I am choosing to use the term function for simplicity’s sake. Nevertheless, the technical term in the Java programming language is method (related to Java’s object-oriented design) and once I get into objects in Chapter 8, I will use the term “method” to describe functions inside of objects.

Before this chapter on functions, I would have translated the above pseudocode into actual code, and placed it inside draw(). Functions, however, will let you approach the problem as follows:

u07-01-9780123944436

The above demonstrates how functions make life easier with clear and easy to manage code. Nevertheless, I am missing an important piece: the function definitions. Calling a function is old hat. You do this all the time when you write line(), rect(), fill(), and so on. Defining a new “made-up” function is going to require some more work on your part.

Before I launch into the details, let’s reflect on why writing your own functions is so important:

 Modularity — Functions break down a larger program into smaller parts, making code more manageable and readable. Once I have figured out how to draw a spaceship, for example, I can take that chunk of spaceship drawing code, store it away in a function, and call upon that function whenever necessary (without having to worry about the details of the operation itself).

 Reusability — Functions allow you to reuse code without having to retype it. What if I want to make a two player Space Invaders game with two spaceships? I can reuse the drawSpaceShip() function by calling it multiple times without having to repeat code over and over.

In this chapter, I will look at some of my previous sketches, written without functions, and demonstrate the power of modularity and reusability by incorporating functions. In addition, I will further emphasize the distinctions between local and global variables, as functions are independent blocks of code that will require the use of local variables. Finally, I will continue to follow Zoog’s story with functions.

Exercise 7-1

Write your answers below.

in07-01-9780123944436

What functions might you write for your Lesson Two Project?What functions might you write in order to program the game Pong?

7-2 “User-defined” functions

In Processing, you have been using functions all along. When you say line(0, 0, 200, 200); you are calling the function line(), a built-in function of the Processing environment. The ability to draw a line by calling the function line() does not magically exist. Someone, somewhere, defined (i.e., wrote the underlying code for) how Processing should display a line. One of Processing’s strengths is its library of available functions, which you have started to explore throughout the first six chapters of this book. Now it’s time to move beyond the built-in functions of Processing and write your own user-defined (a.k.a. “made-up”) functions.

7-3 Defining a function

A function definition (sometimes referred to as a “declaration”) has three parts:

 Return type.

 Function name.

 Arguments.

It looks like this:

returnType functionName(parameters) {

// Code body of function

}

Déjà vu?

Remember when in Chapter 3 I introduced the functions setup() and draw()? Notice that they follow the same format you are learning now.

setup() and draw() are functions you define and are called automatically by Processing in order to run the sketch. All other functions you write have to be called by you.

For now, let’s focus solely on the function name and code body, ignoring return type and parameters.

Here is a simple example:

Example 7-1

Defining a function

void drawBlackCircle() {

fill(0);

ellipse(50, 50, 20, 20);

}

This is a simple function that performs one basic task: drawing an ellipse colored black at coordinate (50,50). Its name — drawBlackCircle() — is arbitrary (I made it up) and its code body consists of two instructions (you can have as much or as little code as you choose). It’s also important to remind ourselves that this is only the definition of the function. The code will never happen unless the function is actually called from a part of the program that is being executed. This is accomplished by referencing the function name, that is, calling a function, as shown in Example 7-2.

Example 7-2

Calling a function

void draw() {

background(255);

drawBlackCircle();

}

Exercise 7-2

Write a function that displays Zoog (or your own design). Call that function from within draw().

in07-01-9780123944436

void setup() {

 size(200, 200);

}

void draw() {

 background(0);

 ____________________________________________________

}

___________________ _________________ ________________ {

______________________________________________________

______________________________________________________

______________________________________________________

______________________________________________________

__________________

7-4 Simple modularity

Let’s examine the bouncing ball example from Chapter 5 and rewrite it using functions, illustrating one technique for breaking a program down into modular parts. Example 5-6 is reprinted here for your convenience.

Example 7-3

Bouncing ball

u07-02-9780123944436

Once I have determined how I want to divide the code up into functions, I can take the pieces out of draw() and insert them into function definitions, calling those functions inside draw(). Functions typically are written below draw().

Example 7-4

Bouncing ball with functions

u07-03-9780123944436

Note how simple draw() has become. The code is reduced to function calls; the detail for how variables change and shapes are displayed is left for the function definitions. One of the main benefits here is the programmer’s sanity. If you wrote this program right before leaving on a two-week vacation in the Caribbean, upon returning with a nice tan, you would be greeted by well-organized, readable code. To change how the ball is rendered, you only need to make edits to the display() function, without having to search through long passages of code or worrying about the rest of the program. For example, try replacing display() with the following:

u07-04a-9780123944436u07-04b-9780123944436

Another benefit of using functions is greater ease in debugging. Suppose, for a moment, that the bouncing ball function was not behaving appropriately. In order to find the problem, I now have the option of turning on and off parts of the program. For example, I might simply run the program with display() only, by commenting out move() and bounce():

u07-05-9780123944436

The function definitions for move() and bounce() still exist, only now the functions are not being called. By adding function calls one by one and executing the sketch each time, I can more easily find the location of the problematic code.

Exercise 7-3

Take any Processing program you have written and modularize it using functions, as above. Use the following space to make a list of functions you need to write.

in07-01-9780123944436

___________________________

___________________________

___________________________

___________________________

___________________________

7-5 Arguments

Just a few pages ago I said “Let’s ignore ReturnType and Arguments.” I did this in order to ease into functions by sticking with the basics. However, functions possess greater powers than simply breaking a program into parts. One of the keys to unlocking these powers are the concepts of arguments and parameters.

Arguments are values that are “passed” into a function. You can think of them as inputs that a function needs to do its job. A function that causes a creature to move a certain number of steps needs to know how many steps you want the creature to move. Instead of merely saying “move,” you might say, “move ten steps,” where “ten” is the argument.

When you define such a “move” function, you are required to give each argument a name. That way, the function can refer to the arguments it receives by the particular name that you specify. To illustrate, let’s rewrite drawBlackCircle() to include a parameter:

u07-06-9780123944436

A parameter is simply a variable declaration inside the parentheses in the function definition. This variable is a local variable (remember the discussion in Section 6-5 on page 104?) to be used in that function (and only in that function). The black circle will be sized according to the value of diameter, which will automatically be assigned the value that you pass the function when you call it. For example, when you say drawBlackCircle(100), the value 100 is the argument. That 100 gets assigned to the diameter parameter, and the function itself uses diameter to draw the circle. When you call drawBlackCircle(80), the argument 80 is assigned to parameter diameter, and the function body then uses diameter to draw the circle.

drawBlackCircle(16); // Draw the circle with a diameter of 16

drawBlackCircle(32); // Draw the circle with a diameter of 32

You could also pass another variable or the result of a mathematical expression (such as mouseX divided by 10) into the function. For example:

drawBlackCircle(mouseX / 10);

This, by the way, is exactly what you did in Chapter 1 when you first started drawing in Processing. To draw a line, for example, you couldn’t just say draw a line. Rather, you had to say draw a line from some (x,y) to some other (x,y). You needed four arguments.

line(10, 25, 100, 75); // Draw a line from (10,25) to (100,75).

The key difference here is that you didn’t write the line() function! The creators of Processing did, and if you delve into the Processing source itself, you’ll find a function definition with four parameters.

void line(float x1, float y1, float x2, float y2) {

 // This functions requires four parameters

 // which define the end points (x1,y1) and (x2,y2)

 // of a line!

}

Parameters pave the way for more flexible, and therefore reusable, functions. To demonstrate this, let’s look at code for drawing a collection of shapes and examine how functions allow you to draw multiple versions of the pattern without retyping the same code over and over.

Leaving Zoog until a bit later, consider the following pattern resembling a car (viewed from above as shown in Figure 7-1):

f07-01-9780123944436

Figure 7-1

u07-07-9780123944436

To draw a second car, I’ll repeat the above code with different values, as shown in Figure 7-2.

f07-02-9780123944436

Figure 7-2

u07-08-9780123944436

It should be fairly apparent where this is going. After all, I am doing the same thing twice — why bother repeating all that code? To escape this repetition, I can move the code into a function that displays the car according to several parameters (position, size, and color).

u07-09-9780123944436

In the draw() function, I then call the drawCar() function three times, passing four arguments each time. See the output in Figure 7-3.

f07-03-9780123944436

Figure 7-3

u07-10-9780123944436

Technically speaking, parameters are the variables that live inside the parentheses in the function definition, that is, void drawCar(int x, int y, int thesize, color c). Arguments are the values passed into the function when it is called, that is, drawCar(80, 175, 40, color(100, 0, 100)). The semantic difference between arguments and parameters is somewhat trivial and you should not be terribly concerned if you confuse the use of the two words from time to time.

The concept to focus on is this ability to pass arguments. You will not be able to advance your programming knowledge unless you are comfortable with this technique.

Let’s go with the word pass. Imagine a lovely, sunny day and you’re playing catch with a friend in the park. You have the ball. You (the main program) call the function (your friend) and pass the ball (the argument). Your friend (the function) now has the ball (the argument) and can use it however he or she pleases (the code itself inside the function). See Figure 7-4.

f07-04-9780123944436

Figure 7-4

Important things to remember about passing arguments

 You must pass the same number of arguments as defined in the function’s parameters.

 When an argument is passed, it must be of the same type as declared within the parameters in the function definition. An integer must be passed into an integer, a floating point into a floating point, and so on.

 The value you pass to a function can be a literal value (20, 5, 4.3, etc.), a variable (x, y, etc.), or the result of an expression (8 + 3,4 * x/2, random(0, 10), etc.)

 Parameters act as local variables to a function and are only accessible within that function.

Exercise 7-4

The following function takes three numbers, adds them together, and prints the sum to the message window.

in07-01-9780123944436

void sum(int a, int b, int c) {

int total = a + b + c;

println(total);

}

Looking at the function definition above, write the code that calls the function.

___________________________

Exercise 7-5

OK, here is the opposite problem. Here is a line of code that assumes a function that takes two numbers, multiplies them together, and prints the result to a message window. Write the function definition that goes with this function call.

in07-01-9780123944436

multiply(5.2, 9.0);

___________________________

___________________________

___________________________

___________________________

in07-01-9780123944436Exercise 7-6: Create a design for a flower. Can you write a function with parameters that vary the flower’s appearance (height, color, number of petals, etc.)? If you call that function multiple times with different arguments, can you create a garden with a variety of flowers?

7-6 Passing a copy

There is a slight problem with the “playing catch” analogy. What I really should have said is the following. Before tossing the ball (the argument), you make a copy of it (a second ball), and pass it to the receiver (the function).

Whenever you pass a primitive value (int, float, char, etc.) to a function, you do not actually pass the value itself, but a copy of that variable. This may seem like a trivial distinction when passing a hard-coded number, but it’s not so trivial when passing a variable.

The following code has a function entitled randomizer() that receives one parameter (a floating point number) and adds a random number between −2 and 2 to it. Here is the pseudocode.

 num is the number 10.

 num is displayed: 10

 A copy of num is passed into the parameter newnum in the function randomizer().

 In the function randomizer():

 a random number is added to newnum.

 newnum is displayed: 10.34232

 num is displayed again: Still 10! A copy was sent into newnum, so num has not changed.

And here is the code:

void setup() {

float num = 10;

println("The number is: " + num);

randomizer(num);

println("The number is: " + num);

}

void randomizer(float newnum) {

newnum = newnum + random(−2, 2);

println("The new number is: " + newnum);

}

Even though the variable num was passed into the variable newnum, which then quickly changed values, the original value of the variable num was not affected because a copy was made.

I like to refer to this process as “pass by copy,” however, it’s more commonly referred to as “pass by value.” This holds true for all primitive data types (the only kinds I’ve covered so far: integer, float, etc.), but is not quite the same with objects, which you will learn about in the next chapter.

This example also provides a nice opportunity to review the flow of a program when using a function. Notice how the code is executed in the order that the lines are written, but when a function is called, the code leaves its current line, executes the lines inside of the function, and then comes back to where it left off. Here is a description of the preceding example’s flow:

1. Set num equal to 10.

2. Print the value of num.

3. Call the function randomizer.

a. Set newnum equal to newnum plus a random number.

b. Print the value of newnum.

4. Print the value of num.

Exercise 7-7

Predict the output of this program by writing out what would appear in the message window.

in07-01-9780123944436

u07-11-9780123944436

7-7 Return type

So far you have seen how functions can separate a sketch into smaller parts, as well as incorporate arguments to make it reusable. However, there is one piece still missing from this discussion, and it is the answer to the question you have been wondering all along: “What does void mean?”

As a reminder, let’s examine the structure of a function definition again:

returnType functionName(parameters) {

// Code body of function

}

OK, now let’s look at one of the functions:

void drawCar(int x, int y, int theSize, color c) {

int offset = theSize/4;

// Draw main car body

rectMode(CENTER);

stroke(200);

fill(c);

// Draw four wheels relative to center

fill(200);

rect(x − offset, y − offset, offset, offset/2);

rect(x + offset, y − offset, offset, offset/2);

rect(x − offset, y + offset, offset, offset/2);

rect(x + offset, y + offset, offset, offset/2);

}

drawCar is the junction name, x is a parameter to the function, and void is the return type. All the functions I have defined so far did not have a return type; this is precisely what void means: no return type. But what is a return type and when might you need one?

Let’s recall for a moment the random() function examined in Chapter 4. I asked the function for a random number between 0 and some value, and random() graciously heeded my request and gave back a random value within the appropriate range. The random() function returned a value. What type of a value? A floating point number. In the case of random(), therefore, its return type is a float.

The return type is the data type that the function returns. In the case of random(), I did not specify the return type, however, the creators of Processing did, and it’s documented on the reference page for random().

Each time the random() function is called, it returns an unexpected value within the specified range. If one argument is passed to the function it will return a float between zero and the value of the argument. The function call random(5) returns values between 0 and 5. If two arguments are passed, it will return a float with a value between the arguments. The function call random(−5, 10.2) returns values between −5 and 10.2.

From http://www.processing.org/reference/random.html

If you want to write your own function that returns a value, you have to specify the type in the function definition. Let’s create a trivially simple example:

u07-12-9780123944436

Instead of writing void as the return type as I have in previous examples, I now write int. This specifies that the function must return a value of type integer. In order for a function to return a value, a return statement is required. A return statement looks like this:

return valueToReturn;

If you do not include a return statement, Processing will give you an error:

 This function must return a result of type int.

As soon as the return statement is executed, the program exits the function and sends the returned value back to the location in the code where the function was called. That value can be used in an assignment operation (to give another variable a value) or in any appropriate expression. See the illustration in Figure 7-5. Here are some examples:

f07-05-9780123944436

Figure 7-5

int x = sum(5, 6, 8);

int y = sum(8, 9, 10) * 2;

int z = sum(x, y, 40);

line(100, 100, 110, sum(x, y, z));

I hate to bring up playing catch in the park again, but you can think of it as follows. You (the main program) throw a copy of a ball to your friend (a function). After your friend catches that ball, he or she thinks for a moment, puts a number inside the ball (the return value) and passes it back to you.

Functions that return values are traditionally used to perform complex calculations that may need to be performed multiple times throughout the course of the program. One example is calculating the distance between two points: (x1,y1) and (x2,y2). The distance between pixels is a very useful piece of information in interactive applications. Processing, in fact, has a built-in distance function that you can use. It’s called dist().

u07-13-9780123944436

This line of code calculates the distance between the mouse location and the point (100, 100). For the moment, let’s pretend Processing did not include this function in its library. Without it, you would have to calculate the distance manually, using the Pythagorean Theorem, as shown in Figure 7-6.

f07-06-9780123944436

Figure 7-6

float dx = mouseX − 100;

float dy = mouseY − 100;

float d = sqrt(dx*dx + dy*dy);

If you wanted to perform this calculation many times over the course of a program with many different pairs of coordinates, it would be easier to move it into a function that returns the value d.

u07-14-9780123944436

Note the use of the return type float. Again, I do not have to write this function because Processing supplies it for me. But since I did, I can now show an example that makes use of this function.

u07-15-9780123944436

Figure 7-7

Example 7-5

Using a function that returns a value, distance

u07-16-9780123944436

Exercise 7-8

Write a function that takes one argument — F for Fahrenheit — and computes the result of the following equation (converting the temperature to Celsius). Hint: in Processing if you divide an integer by an integer you will get an integer, same with floating point! In other words, 1/2 evaluates to 0 while 1.0/2.0 evaluates to 0.5.

in07-01-9780123944436

// Formula: C = (F − 32) * (5/9)

______ convertToCelsius(float ________) {

______ _______ = ____________________

_____________________________________

}

7-8 Zoog reorganization

Zoog is now ready for a fairly major overhaul.

 Reorganize Zoog with two functions: drawZoog() and jiggleZoog(). Just for variety, I am going to have Zoog jiggle (move randomly in both the x and y directions) instead of bouncing back and forth.

 Incorporate parameters so that Zoog’s jiggliness is determined by the mouseX position and Zoog’s eye color is determined by Zoog’s distance to the mouse.

u07-17-9780123944436

Figure 7-8

Example 7-6

Zoog with functions

u07-18a-9780123944436u07-18b-9780123944436

in07-01-9780123944436Exercise 7-9: Write a function that draws Zoog based on a set of parameters. Some ideas are: Zoog’s x and y coordinates, its width and height, eye color.

Exercise 7-10

Another idea (if you’re feeling tired of Zoog) is to create a design for a spaceship and draw several to the screen with slight variations based on arguments you pass to a function. Here’s a screenshot and the beginnings of some example code.

in07-01-9780123944436

u07-19-9780123944436
u07-20-9780123944436

___________________________

___________________________

___________________________

___________________________

___________________________

___________________________

___________________________

in07-01-9780123944436Exercise 7-11: Rewrite your Lesson Two Project using functions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.199.162