Chunk 14: Functions 1
Up to this point all our coding has been linear: that is to say our sketches start at the top and work their way right through until they get to the bottom with everything spelt out in full.
There are times when we’ve almost repeated the same pieces of code multiple times within the same sketch. Wouldn’t it be great if there was a way that you could just write that bit once and then tell the computer to use it again and again? This is where ‘functions’ come in.
A function is a mini program that can be used over and over by a main program. Every function has a name and, optionally, has one or more arguments passed to it. The basic structure of a function is:
void function_name ( argument_list ) {
// function content
}
The ‘void’ indicates that the function does not return any value; the function name should follow the normal naming conventions that you would expect for any identifier; the round brackets enclose any arguments that the function will be expecting, these will be examined shortly; finally, the braces are used to mark the beginning and end of the code that comprises the function content, this can range from a simple statement of a single line to a complex routine of many lines.
The round brackets and braces must always be present even if they have nothing to enclose: that is to say, if there are no arguments, the round brackets are still present but with nothing between them; and if there is no code (if the function is a placeholder to be filled in later for example) then the braces are still present. In the latter case it is usual to insert a comment as a reminder about the empty function!
The argument list is where all the work is done: this is where all the differences are made for a function. Rather than always doing the same thing, using arguments allows us to influence the way that the function will operate. Arguments are lists in a similar fashion to the way that variables are declared except that they are separated by commas: so you would declare a variable type followed by a variable name, and then a comma followed by the same sequence repeated for however many arguments are required. If you ever find yourself writing a function with more than five or six arguments though, then your function is most likely trying to do too much and should be examined to see if it can be broken down into two or more simpler functions because the more complicated a function is, the harder it is to debug and the easier it is for an error to split through unnoticed.
Let us look at an example: we can specialise the standard ‘ellipse’ routine to make our own function to draw a circle, which we shall call ‘drawCircle’, to save having to repeat the third argument every time we want a circle and avoid the possibility of mistyping the repeat.
We already know what arguments we are going to need; we are mimicking the first two arguments of the ‘ellipse’ routine, but replacing the third and fourth with a single ‘diameter’. So our argument list is going to be ‘float x, float y, float diameter’.
These arguments we can pass straight on to the ellipse routine, passing the diameter for both the width and height arguments, without any additional processing, so our function will look like this:
void drawCircle(float x, float y, float diameter) {
ellipse(x,y,diameter,diameter);
}
A similar function named ‘drawSquare’ would specialise the rectangle routine as follows:
void drawSquare(float x, float y, float width) {
rectangle(x,y,width,width);
}
Now we have two functions, how do we use them? Well, they are used just like any normal routine, you give the function name and arguments in round brackets and the computer executes the function contents at that point in your code.
Let us write a short sketch to draw a circle on top of a square using the functions that we’ve just declared.
void setup(){
size(400,400);
background(255);
drawSquare(200,200,150);
drawCircle(200,200,150);
}
When we execute this we find that it’s not quite what we want.
The circle draws with the (x,y) arguments specifying the centre of the circle, whereas the square draws with the (x,y) arguments specifying the top left corner.
It might be useful to have a further function, say ‘drawSquareCentred’ that uses the (x,y) arguments to specify the centre in the same way as the circle.
Now, the only difference between the normal square and the ‘centred’ square is that an offset is going to be applied to the x and y arguments; so we’re going to use the fact that the functions become part of the system to expand on drawSquare and not repeat the rectangle command.
Our drawSquareCentred function is going to use a ‘local’ variable. A local variable is one that is declared like any other variable, but within the function braces, it cannot be accessed outside of the function itself, it is completely self contained: it is said to have a scope extending to the end of the function.
void drawSquareCentred(float x, float y, float width) {
float halfWidth = width/2 ;
drawSquare(x-halfWidth,y-halfWidth,width);
}
If we now modify our short test sketch to replace ‘drawSquare’ with drawSquareCentred’ we get the result we originally intended:
No comments:
Post a Comment