This module will focus on the creation of functions, self-contained named blocks of programming code.
Until now we’ve been using Processing’s built-in functions like line, size and ellipse to write our programs, but it’s also possible to create our own functions.
Custom functions allow us to remove redundant code from our programs and make our source code easier to read and update.
Upon completion of this module, you should be able to:
A function is a named, independent section of code that performs a specific task and optionally returns a computed value.
Functions are the verbs of computer programming. They do things.
They increase:
In our Intro to Processing module we learnt how to use Processing’s built in functions. We execute a function by name followed by open and close parenthesis. Many functions allow us to control their behaviour by including a list of comma-separated arguments within the parentheses.
println( "This string is the argument of the println function." );
line( 0, 0, 100, 100 ); // Draw a diagonal line.
fill( 0 ); // Set the fill colour to black.
circle( 50, 50, 40, 40 ); // Draw a black circle.
What does this code do?
for( int i = 60; i > 0; i -= 10 ) {
ellipse( 50, 50, i, i );
}
Writing readable code is important. Wouldn’t it be nice if we could describe this code with an appropriate name?
Paste this code into Processing to see if you were able to correctly determine what it does.
A generic function looks like this:
returnType functionName( parameters ) {
// Code goes here.
}
Let’s give our target drawing code a name by defining a function:
void drawTarget() {
for( int i = 60; i > 0; i -= 10 ) {
ellipse( 50, 50, i, i );
}
}
Function names are written in camelCase, just like variable names.
A return type of ”void” means that our function will not return a computed value to the calling program. Later in this module we’ll explore functions that do return values.
Note: The code within a function’s code block will only be executed when the function is called.
It is important that we give our functions descriptive names. A well thought-out name allows readers of our code to understand the purpose of a function without having to look at the function’s code. This improves the readability of our code.
Our drawTarget function says exactly what it does, it draws a target!
In our Booleans and Conditionals assignment you were introduced to two special functions called setup and draw.
Whenever we wish to use custom functions in our code, we must use one or both of these special functions.
void drawTarget() {
for( int i = 60; i > 0; i -= 10 ) {
ellipse( 50, 50, i, i );
}
}
void setup() {
drawTarget(); // Execute or "call" our custom function.
}
Note that we always include the open and close parentheses when we call the function.
If you write a Processing sketch that includes a custom function and you do not use a setup or draw function you will get an error when trying to run your code. Here’s an example of some code that would not run:
void drawTarget() {
for( int i = 60; i > 0; i -= 10 ) {
ellipse( 50, 50, i, i );
}
}
drawTarget();
If you tried to run the above code you’d get an error that say:
It looks like you're mixing "active" and "static" modes."
Currently, our target drawing function does the same thing every time it’s called. What if we could specify where we wanted the target drawn on the canvas?
void drawTarget( int x, int y ) {
for( int i = 60; i > 0; i -= 10 ) {
ellipse( x, y, i, i );
}
}
Here we’ve added two integer parameters to the function definition. These parameters act like variable declarations. When we call the function, we need to provide one argument for each function parameter.
void setup() {
drawTarget(20, 25);
}
The integer “20” is the first argument and is loaded into the parameter x. The integer “25” is the second argument and is loaded into the parameter y.
We can make our function even more flexible by adding another parameter for the size of the target:
void drawTarget( int x, int y, int size ) {
for( int i = size; i > 0; i -= 10 ) {
ellipse( x, y, i, i );
}
}
Our drawTarget function could be further enhanced to include a parameter for the colour of the target. Here’s a simple drawing program that makes use of this enhanced version of our function.
void setup() {
size( 400, 400 );
}
void draw() {
if ( mousePressed ) {
drawTarget( mouseX, mouseY, 60, #6666EE );
} else {
drawTarget( mouseX, mouseY, 60, #66EE66 );
}
}
void drawTarget( int x, int y, int size, color c ) {
fill( c );
for( int i = size; i > 0; i -= 10 ) {
ellipse( x, y, i, i );
}
}
Hover your mouse over the above canvas area. Holding down the mouse button changes the target colour.
Functions can return computed values to the program that calls them. Our drawTarget function doesn’t return any data so it was assigned a return type of ”void”.
We use the keyword ”return” to return data from a function. The data we return must match the return type of the function.
The return type must be a valid variable type like int, float, String, etc.
int cubed( int x ) {
return x * x * x; // return x to the power of 3 as an integer.
}
void setup() {
int ten_cubed = cubed( 10 );
println( "Ten to the power of three is " + ten_cubed );
}
You should consider functions to be completely “stand alone” when it comes to variables. Variables created within a function are called local variables. These local variables are not accessible from outside of the function.
In the example below, the variable x_cubed is a local variable, accessible only within the cubed() function. Trying to access it from outside the function will result in an error.
int cubed( int x ) {
int x_cubed = x * x * x; // The variable x_cubed is accessible only within the function.
return x_cubed;
}
void setup() {
int ten_cubed = cubed( 10 );
println( "Ten to the power of three is " + ten_cubed );
println( x_cubed ); // Results in error: "Cannot find anything called 'x_cubed'"
}
Function parameters are also not accessible outside the function. Trying to access the cubed() function’s parameter x from outside the function will result in an error, as shown below.
void setup() {
int ten_cubed = cubed( 10 );
println( "Ten to the power of three is " + ten_cubed );
println( x ); // Results in an error!
}
Imagine we wanted to code a Space Invaders-type game. We might start out by coding the display and controls for the player spaceship.
Notice that the draw() function only contains three function calls. One to the built in function background and then two custom functions.
int currentShipXPosition;
void setup() {
size(400,300);
currentShipXPosition = width/2;
}
void draw() {
background(200);
drawSpaceship(currentShipXPosition);
currentShipXPosition = calculateNextShipXPosition(currentShipXPosition);
}
The drawSpaceship function is defined with a single parameter and a return type of ”void”.
void drawSpaceship(int topOfShipX) {
// Drawing code goes here.
}
The topOfShipX parameter controls the x-axis location of where the ship will be drawn on the canvas.
The calculateNextShipXPosition function takes in the current X position of our ship (the currentShipXPosition parameter). It then calculates and returns a new X position based on user input.
int calculateNextShipXPosition( int currentShipXPosition ) {
// Calculate and return the next x-axis position
// based on user input.
}
The actual implementation of these two functions isn’t important. The important thing to realize is that by using functions we’ve assigned descriptive names to potentially complex pieces of code.
Click on the square below and then use the left and right arrow keys to control the “spaceship” (aka the triangle).
To view the full source code, including the drawSpaceship and calculateNextShipXPosition functions, click on the “source” link above.
You will sometimes hear programmers refer to functions as procedures, methods, or even subroutines.
In some programming languages there is a distinction between a procedure (which performs a task) and a function (which calculates a value). This distinction does not exist in Processing.
Object-oriented programming (OOP) is a programming style that represents concepts as “objects” that have data fields (attributes that describe the object) and associated functions.
When you start coding Object Oriented Java in the BIT program you will use the term method to refer to functions associated with objects.
In a sense, you can think of the above Spaceship Processing sketch as an object representing a spaceship. The attributes that describe this spaceship object are the integer variables defined at the top of the sketch. The associated methods are the two custom functions used to display and move the ship.
This is the final module in the course. :)
I hope you have enjoyed your introduction to the Java programming language by way of Processing.