epubjs
Version:
Render ePub documents in the browser, across many devices
618 lines (363 loc) • 23.9 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="utf-8"/>
<title>Getting Started with Processing</title>
<script type="text/javascript">
if(!window.atlasplugins) window.atlasplugins = {}
atlasplugins.codeMirrorSettings = {
theme: "3024-day"
}
</script>
<link href="http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700" rel="stylesheet" type="text/css"> </link>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"> </script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script>
<link rel="stylesheet" type="text/css" href="theme/html/html.css"/>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/4.4.0/codemirror.min.css"/>
<link rel="stylesheet" type="text/css" href="https://d2uogd9jz9k9zm.cloudfront.net/processingjs-0.0.3.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/4.4.0/codemirror.min.js" type="text/javascript"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/4.5.0/mode/clike/clike.min.js" type="text/javascript"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js" type="text/javascript"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/processing.js/1.4.8/processing.min.js" type="text/javascript"> </script>
<script src="https://d2uogd9jz9k9zm.cloudfront.net/processingjs-0.0.3.min.js" type="text/javascript"> </script>
<script type="text/javascript">
$(function() {
// Make all non runnable examples readonly codemirrors
$('pre:not(*[data-executable], .CodeMirror pre)').each(function(i, el) {
var textArea = $('<textarea>' + el.innerHTML + '</textarea>')
$(el).replaceWith(textArea);
var editor = CodeMirror.fromTextArea(textArea[0], {
mode: "text/x-java",
theme: "3024-day",
readOnly: true,
viewportMargin: 0
});
});
});
</script>
<style type="text/css">
/* This needs to come last to set auto height, and html.css is always included first */
.CodeMirror {
height: auto;
font-size: 14px;
padding: 15px;
border-radius: 5px;
}
.CodeMirror-scroll {
overflow-y: hidden;
overflow-x: auto;
height: auto;
}
</style>
<script type="text/javascript" src="theme/html/epub.js"> </script>
<script type="text/javascript" src="theme/html/reader.js"> </script>
</head>
<body data-type="book" id="viewer">
<section data-type="chapter" data-pdf-bookmark="Chapter 8. Functions" id="functions">
<h1>Functions</h1>
<p>Functions are the basic building blocks for Processing programs. They have appeared in every example we’ve presented. For instance, we’ve frequently used the <em>size()</em> function, the <em>line()</em> function, and the <em>fill()</em> function. This chapter shows how to write new functions to extend the capabilities of Processing beyond its built-in features.</p>
<p>The power of functions is modularity. Functions are independent software units that are used to build more complex programs—like LEGO® bricks, where each type of brick serves a specific purpose, and making a complex model requires using the different parts together. As with functions, the true power of these bricks is the ability to build many different forms from the same set of elements. The same group of LEGOs that makes a spaceship can be reused to construct a truck, a skyscraper, and many other objects.</p>
<p>Functions are helpful if you want to draw a more complex shape like a tree over and over. The function to draw the tree shape would be made up of Processing’s built-in commands, like <em>line()</em>, that create the form. After the code to draw the tree is written, you don’t need to think about the details of tree drawing again—you can simply write <em>tree()</em> (or whatever you named the function) to draw the shape. Functions allow a complex sequence of statements to be abstracted, so you can focus on the higher-level goal (such as drawing a tree), and not the details of the implementation (the <em>line()</em> commands that define the tree shape). Once a function is defined, the code inside the function need not be repeated again.</p>
<section data-type="sect1" data-pdf-bookmark="Function Basics" id="function_basics">
<h1>Function Basics</h1>
<p>A computer runs a program one line at a time. When a function is run, the computer jumps to where the function is defined and runs the code there, then jumps back to where it left off.</p>
<section data-type="sect2" data-pdf-bookmark="Example 8-1: Roll the Dice" id="example_8-1_colon_roll_the_dice">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_01">Example 8-1: Roll the Dice</a></h2>
<p>This behavior is illustrated with the <em>rollDice()</em> function written for this example. When a program starts, it runs the code in <em>setup()</em> and then stops. The program takes a detour and runs the code inside <em>rollDice()</em> each time it appears:</p>
<pre data-type="programlisting">void setup() {
println("Ready to roll!");
rollDice(20);
rollDice(20);
rollDice(6);
println("Finished.");
}
void rollDice(int numSides) {
int d = 1 + int(random(numSides));
println("Rolling... " + d);
}</pre>
<p>The two lines of code in <em>rollDice()</em> select a random number between 1 and the number of sides on the dice, and prints that number to the Console. Because the numbers are random, you’ll see different numbers each time the program is run:</p>
<pre data-type="programlisting">Ready to roll!
Rolling... 20
Rolling... 11
Rolling... 1
Finished.</pre>
<p>Each time the <em>rollDice()</em> function is run inside <em>setup()</em>, the code within the function runs from top to bottom, then the program continues on the next line within <em>setup()</em>.</p>
<p>The <em>random()</em> function (described in <a data-type="xref" href="ch07.html#random">“Random”</a>) returns a number from 0 up to (but not including) the number specified. So <em>random(6)</em> returns a number between 0 and 5.99999. . . . Because <em>random()</em> returns a <em>float</em> value, we also use <em>int()</em> to convert it to an integer. So <em>int(random(6))</em> will return 0, 1, 2, 3, 4, or 5. Then we add 1 so that the number returned is between 1 and 6 (like a die). Like many other cases in this book, counting from 0 makes it easier to use the results of <em>random()</em> with other calculations.</p>
</section>
<section data-type="sect2" data-pdf-bookmark="Example 8-2: Another Way to Roll" id="example_8-2_colon_another_way_to_roll">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_02">Example 8-2: Another Way to Roll</a></h2>
<p>If an equivalent program were written without the <em>rollDice()</em> function, it might look like this:</p>
<pre data-type="programlisting">void setup() {
println("Ready to roll!");
int d1 = 1 + int(random(20));
println("Rolling... " + d1);
int d2 = 1 + int(random(20));
println("Rolling... " + d2);
int d3 = 1 + int(random(6));
println("Rolling... " + d3);
println("Finished.");
}</pre>
<p>The <em>rollDice()</em> function in <a data-type="xref" href="#example_8-1_colon_roll_the_dice">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_01">Example 8-1: Roll the Dice</a>”</a> makes the code easier to read and maintain. The program is clearer, because the name of the function clearly states its purpose. In this example, we see the <em>random()</em> function in <em>setup()</em>, but its use is not as obvious. The number of sides on the die is also clearer with a function: when the code says <em>rollDice(6)</em>, it’s obvious that it’s simulating the roll of a six-sided die. Also, <a data-type="xref" href="#example_8-1_colon_roll_the_dice">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_01">Example 8-1: Roll the Dice</a>”</a> is easier to maintain, because information is not repeated. The phase <code>Rolling…</code> is repeated three times here. If you want to change that text to something else, you would need to update the program in three places, rather than making a single edit inside the <em>rollDice()</em> function. In addition, as you’ll see in <a data-type="xref" href="#example_8-5_colon_an_owl_function">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_05">Example 8-5: An Owl Function</a>”</a>, a function can also make a program much shorter (and therefore easier to maintain and read), which helps reduce the potential number of bugs.</p>
</section>
</section>
<section data-type="sect1" data-pdf-bookmark="Make a Function" id="make_a_function">
<h1>Make a Function</h1>
<p>In this section, we’ll draw an owl to explain the steps involved in making a function.</p>
<section data-type="sect2" data-pdf-bookmark="Example 8-3: Draw the Owl" id="example_8-3_colon_draw_the_owl">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_03">Example 8-3: Draw the Owl</a></h2>
<p>First we’ll draw the owl without using a function:</p>
<figure>
<img src="images/Ex_08_03.png" alt="Ex 08 03"/>
<figcaption/>
</figure>
<pre data-type="programlisting">void setup() {
size(480, 120);
smooth();
}
void draw() {
background(204);
translate(110, 110);
stroke(0);
strokeWeight(70);
line(0, −35, 0, −65); // Body
noStroke();
fill(255);
ellipse(−17.5, −65, 35, 35); // Left eye dome
ellipse(17.5, −65, 35, 35); // Right eye dome
arc(0, −65, 70, 70, 0, PI); // Chin
fill(0);
ellipse(−14, −65, 8, 8); // Left eye
ellipse(14, −65, 8, 8); // Right eye
quad(0, −58, 4, −51, 0, −44, −4, −51); // Beak
}</pre>
<p>Notice that <em>translate()</em> is used to move the origin (0,0) to 110 pixels over and 110 pixels down. Then the owl is drawn relative to (0,0), with its coordinates sometimes positive and negative as it’s centered around the new 0,0 point. See <a data-type="xref" href="#the_owl_apostrophy_s_coordinates">Figure 8-1</a>.</p>
<figure id="the_owl_apostrophy_s_coordinates">
<img src="images/Fig_08_01.png" alt="Fig 08 01"/>
<figcaption>The owl’s coordinates.</figcaption>
</figure>
</section>
<section data-type="sect2" data-pdf-bookmark="Example 8-4: Two’s Company" id="example_8-4_colon_two_apostrophy_s_compa">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_04">Example 8-4: Two’s Company</a></h2>
<p>The code presented in <a data-type="xref" href="#example_8-3_colon_draw_the_owl">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_03">Example 8-3: Draw the Owl</a>”</a> is reasonable if there is only one owl, but when we draw a second, the length of the code is nearly doubled:</p>
<figure>
<img src="images/Ex_08_04.png" alt="Ex 08 04"/>
<figcaption/>
</figure>
<pre data-type="programlisting">void setup() {
size(480, 120);
smooth();
}
void draw() {
background(204);
// Left owl
translate(110, 110);
stroke(0);
strokeWeight(70);
line(0, −35, 0, −65); // Body
noStroke();
fill(255);
ellipse(−17.5, −65, 35, 35); // Left eye dome
ellipse(17.5, −65, 35, 35); // Right eye dome
arc(0, −65, 70, 70, 0, PI); // Chin
fill(0);
ellipse(−14, −65, 8, 8); // Left eye
ellipse(14, −65, 8, 8); // Right eye
quad(0, −58, 4, −51, 0, −44, −4, −51); // Beak
// Right owl
translate(70, 0);
stroke(0);
strokeWeight(70);
line(0, −35, 0, −65); // Body
noStroke();
fill(255);
ellipse(−17.5, −65, 35, 35); // Left eye dome
ellipse(17.5, −65, 35, 35); // Right eye dome
arc(0, −65, 70, 70, 0, PI); // Chin
fill(0);
ellipse(−14, −65, 8, 8); // Left eye
ellipse(14, −65, 8, 8); // Right eye
quad(0, −58, 4, −51, 0, −44, −4, −51); // Beak
}</pre>
<p>The program grew from 21 lines to 34, because the code to draw the first owl was cut and pasted into the program and a <em>translate()</em> was inserted to move it to the right 70 pixels. This is a tedious and inefficient way to draw a second owl, not to mention the headache of adding a third owl with this method. But duplicating the code is unnecessary, because this is the type of situation where a function can come to the rescue.</p>
</section>
<section data-type="sect2" data-pdf-bookmark="Example 8-5: An Owl Function" id="example_8-5_colon_an_owl_function">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_05">Example 8-5: An Owl Function</a></h2>
<p>In this example, a function is introduced to draw two owls with the same code. If we make the code that draws the owl to the screen into a new function, the code need only appear once in the program:</p>
<figure>
<img src="images/Ex_08_05.png" alt="Ex 08 05"/>
<figcaption/>
</figure>
<pre data-type="programlisting">void setup() {
size(480, 120);
smooth();
}
void draw() {
background(204);
owl(110, 110);
owl(180, 110);
}
void owl(int x, int y) {
pushMatrix();
translate(x, y);
stroke(0);
strokeWeight(70);
line(0, −35, 0, −65); // Body
noStroke();
fill(255);
ellipse(−17.5, −65, 35, 35); // Left eye dome
ellipse(17.5, −65, 35, 35); // Right eye dome
arc(0, −65, 70, 70, 0, PI); // Chin
fill(0);
ellipse(−14, −65, 8, 8); // Left eye
ellipse(14, −65, 8, 8); // Right eye
quad(0, −58, 4, −51, 0, −44, −4, −51); // Beak
popMatrix();
}</pre>
<p>You can see from the illustrations that this example and <a data-type="xref" href="#example_8-4_colon_two_apostrophy_s_compa">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_04">Example 8-4: Two’s Company</a>”</a> have the same result, but this example is shorter, because the code to draw the owl appears only once, inside the aptly named <em>owl()</em> function. This code runs twice, because it’s called twice inside <em>draw()</em>. The owl is drawn in two different locations because of the parameters passed into the function that set the x- and y-coordinates.</p>
<p>Parameters are an important part of functions, because they provide flexibility. We saw another example in the <em>rollDice()</em> function; the single parameter named <em>numSides</em> made it possible to simulate a 6-sided die, a 20-sided die, or a die with any number of sides. This is just like many other Processing functions. For instance, the parameters to the <em>line()</em> function make it possible to draw a line from any pixel on screen to any other pixel. Without the parameters, the function would be able to draw a line only from one fixed point to another.</p>
<p>Each parameter has a data type (such as <em>int</em> or <em>float</em>), because each parameter is a variable that’s created each time the function runs. When this example is run, the first time the owl function is called, the value of the <em>x</em> parameter is 110, and <em>y</em> is also 110. In the second use of the function, the value of <em>x</em> is 180 and <em>y</em> is again 110. Each value is passed into the function and then wherever the variable name appears within the function, it’s replaced with the incoming value.</p>
<p>Make sure the values passed into a function match the data types of the parameters. For instance, if the following appeared inside the <em>setup()</em> for <a data-type="xref" href="#example_8-5_colon_an_owl_function">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_05">Example 8-5: An Owl Function</a>”</a>:</p>
<pre data-type="programlisting">owl(110.5, 120.2);</pre>
<p>This would create an error, because the data type for the <em>x</em> and <em>y</em> parameters is <em>int</em>, and the values 110.5 and 120.2 are <em>float</em> values.</p>
</section>
<section data-type="sect2" data-pdf-bookmark="Example 8-6: Increasing the Surplus Population" id="example_8-6_colon_increasing_the_surplus">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_06">Example 8-6: Increasing the Surplus Population</a></h2>
<p>Now that we have a basic function to draw the owl at any location, we can draw many owls efficiently by placing the function within a <em>for</em> loop and changing the first parameter each time through the loop:</p>
<figure>
<img src="images/Ex_08_06.png" alt="Ex 08 06"/>
<figcaption/>
</figure>
<pre data-type="programlisting">void setup() {
size(480, 120);
smooth();
}
void draw() {
background(204);
for (int x = 35; x &lt; width + 70; x += 70) {
owl(x, 110);
}
}
// Insert owl() function from Example 8-5</pre>
<p>It’s possible to keep adding more and more parameters to the function to change different aspects of how the owl is drawn. Values could be passed in to change the owl’s color, rotation, scale, or the diameter of its eyes.</p>
</section>
<section data-type="sect2" data-pdf-bookmark="Example 8-7: Owls of Different Sizes" id="example_8-7_colon_owls_of_different_size">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_07">Example 8-7: Owls of Different Sizes</a></h2>
<p>In this example, we’ve added two parameters to change the gray value and size of each owl:</p>
<figure>
<img src="images/Ex_08_07.png" alt="Ex 08 07"/>
<figcaption/>
</figure>
<pre data-type="programlisting">void setup() {
size(480, 120);
smooth();
}
void draw() {
background(204);
randomSeed(0);
for (int i = 35; i &lt; width + 40; i += 40) {
int gray = int(random(0, 102));
float scalar = random(0.25, 1.0);
owl(i, 110, gray, scalar);
}
}
void owl(int x, int y, int g, float s) {
pushMatrix();
translate(x, y);
scale(s); // Set the size
stroke(g); // Set the gray value
strokeWeight(70);
line(0, −35, 0, −65); // Body
noStroke();
fill(255-g);
ellipse(−17.5, −65, 35, 35); // Left eye dome
ellipse(17.5, −65, 35, 35); // Right eye dome
arc(0, −65, 70, 70, 0, PI); // Chin
fill(g);
ellipse(−14, −65, 8, 8); // Left eye
ellipse(14, −65, 8, 8); // Right eye
quad(0, −58, 4, −51, 0, −44, −4, −51); // Beak
popMatrix();
}</pre>
</section>
</section>
<section data-type="sect1" data-pdf-bookmark="Return Values" id="return_values">
<h1>Return Values</h1>
<p>Functions can make a calculation and then return a value to the main program. We’ve already used functions of this type, including <em>random()</em> and <em>sin()</em>. Notice that when this type of function appears, the return value is usually assigned to a variable:</p>
<pre data-type="programlisting">float r = random(1, 10);</pre>
<p>In this case, <em>random()</em> returns a value between 1 and 10, which is then assigned to the <em>r</em> variable.</p>
<p>A function that returns a value is also frequently used as a parameter to another function. For instance:</p>
<pre data-type="programlisting">point(random(width), random(height));</pre>
<p>In this case, the values from <em>random()</em> aren’t assigned to a variable—they are passed as parameters to <em>point()</em> and used to position the point within the window.</p>
<section data-type="sect2" data-pdf-bookmark="Example 8-8: Return a Value" id="example_8-8_colon_return_a_value">
<h2><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Ex_08_08">Example 8-8: Return a Value</a></h2>
<p>To make a function that returns a value, replace the keyword <em>void</em> with the data type that you want the function to return. In your function, specify the data to be passed back with the keyword <em>return</em>. For instance, this example includes a function called <em>calculateMars()</em> that calculates the weight of a person or object on our neighboring planet:</p>
<pre data-type="programlisting">void setup() {
float yourWeight = 132;
float marsWeight = calculateMars(yourWeight);
println(marsWeight);
}
float calculateMars(float w) {
float newWeight = w * 0.38;
return newWeight;
}</pre>
<p>Notice the data type <em>float</em> before the function name to show that it returns a floating-point value, and the last line of the block, which returns the variable <em>newWeight</em>. In the second line of <em>setup()</em>, that value is assigned to the variable <em>marsWeight</em>. (To see your own weight on Mars, change the value of the <em>yourWeight</em> variable to your weight.)</p>
</section>
</section>
<section data-type="sect1" data-pdf-bookmark="Robot 6: Functions" id="robot_6_colon_functions">
<h1><a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Robot6_Functions">Robot 6: Functions</a></h1>
<figure>
<img src="images/NRobot_Functions.png" alt="NRobot Functions"/>
<figcaption/>
</figure>
<p>In contrast to Robot 2 (see <a data-type="xref" href="ch04.html#robot_2_colon_variables">“<a href="http://examples.oreilly.com/0636920000570/interactive_examples/index.php?example=Robot2_Variables">Robot 2: Variables</a>”</a> in <a data-type="xref" href="ch04.html#variables">Chapter 4</a>), this example uses a function to draw four robot variations within the same program. Because the <em>drawRobot()</em> function appears four times within <em>draw()</em>, the code within the <em>drawRobot()</em> block is run four times, each time with a different set of parameters to change the position and height of the robot’s body.</p>
<p>Notice how what were global variables in Robot 2 have now been isolated within the <em>drawRobot()</em> function. Because these variables apply only to drawing the robot, they belong inside the curly braces that define the <em>drawRobot()</em> function block. Because the value of the <em>radius</em> variable doesn’t change, it need not be a parameter. Instead, it is defined at the beginning of <em>drawRobot()</em>:</p>
<pre data-type="programlisting">void setup() {
size(720, 480);
smooth();
strokeWeight(2);
ellipseMode(RADIUS);
}
void draw() {
background(204);
drawRobot(120, 420, 110, 140);
drawRobot(270, 460, 260, 95);
drawRobot(420, 310, 80, 10);
drawRobot(570, 390, 180, 40);
}
void drawRobot(int x, int y, int bodyHeight, int neckHeight) {
int radius = 45;
int ny = y - bodyHeight - neckHeight - radius;
// Neck
stroke(102);
line(x+2, y-bodyHeight, x+2, ny);
line(x+12, y-bodyHeight, x+12, ny);
line(x+22, y-bodyHeight, x+22, ny);
// Antennae
line(x+12, ny, x-18, ny-43);
line(x+12, ny, x+42, ny-99);
line(x+12, ny, x+78, ny+15);
// Body
noStroke();
fill(102);
ellipse(x, y-33, 33, 33);
fill(0);
rect(x-45, y-bodyHeight, 90, bodyHeight-33);
fill(102);
rect(x-45, y-bodyHeight+17, 90, 6);
// Head
fill(0);
ellipse(x+12, ny, radius, radius);
fill(255);
ellipse(x+24, ny-6, 14, 14);
fill(0);
ellipse(x+24, ny-6, 3, 3);
fill(153);
ellipse(x, ny-8, 5, 5);
ellipse(x+30, ny-26, 4, 4);
ellipse(x+41, ny+6, 3, 3);
}</pre>
</section>
</section>
</body>
</html>