Functions
Give a piece of your drawing a name so you can use it again. Write your own functions, hand them inputs, and build a whole scene out of named parts.
1Your First Function
Give a piece of your drawing a name, and everyFrame turns into a list of what is in the picture. A function only runs when something says its name.
Lesson — read before you start
This topic is where you write your own. It takes two parts, and they are easy to mix up.
The definition says what the name means. It goes at the top level of your sketch, outside everyFrame, and on its own it draws nothing at all:
function drawTree() {
shapeColour(BROWN);
rectangle(190, 250, 20, 80);
shapeColour(GREEN);
circle(200, 200, 130);
}
The call is the name with brackets after it, and that is what makes those lines run:
drawTree();
A definition with no call is the most common thing to get wrong, and it is completely silent — no error, no shape, just an empty picture. If something has vanished, look for the call first.
The two names have to match letter for letter. When they do not, the sketch stops and the Results panel tells you the name it could not find: drawHous is not defined. That is a helpful message rather than a telling-off, because it names the exact thing to fix.
Once you have a few names, everyFrame stops being a wall of numbers and starts reading like a list of what is in the picture:
function everyFrame(){
backgroundColour(CYAN);
drawSea();
drawSun();
drawBoat();
}
Those calls run top to bottom, just as your drawing lines always have, so the sea is painted before the boat that floats on it. It makes no difference what order the definitions sit in further up the file — only the order of the calls.
One thing to watch: a function is not a sealed box. If it sets shapeColour inside itself, the pen is still that colour after the call has finished. And if it sets no colour at all, it draws with whatever pen you were holding when you called it.
There is one thing this topic cannot do. Every call to drawTree() draws in exactly the same place, because nothing in drawTree() or in the call says where. Saying it twice gets you one tree. The next topic fixes that, and it is where writing your own functions starts to pay.
2Use It Again
Put a name in a function's brackets and every call gets to fill it in. One set of drawing lines, called again and again with different numbers, draws the same thing in as many places as you like.
Lesson — read before you start
The fix is a name in the definition's brackets:
function drawTree(x) {
shapeColour(BROWN);
rectangle(x - 10, 250, 20, 80);
shapeColour(GREEN);
circle(x, 200, 110);
}
That name — x here, though you can call it anything — is an empty box. It has no value of its own. The call fills it in:
drawTree(100);
drawTree(300);
The first call puts 100 into x and runs the body, so a tree is drawn at 100. The second puts 300 in and runs the same body again, so a tree is drawn at 300. One function, two trees, and the drawing lines written once.
The name is called an input, and the number a call hands over is called an argument.
Three things follow from that, and each one is worth watching for.
Everything in the body that should move has to mention the input. The trunk is written x - 10, not 190, or it stays where it is written while the leaves move off without it.
The names have to match. The body can only use the name the brackets introduce; use a different one and the sketch stops with that name is not defined.
The brackets have to be filled. A call that leaves them empty gives the input no value, and every shape that depends on it is drawn nowhere at all — with no error to tell you. If a shape has vanished, check what the call handed over.
An input does not have to be a position. It is just a number, so it can be a size instead, and one input can feed several parts of one drawing at once. The argument does not have to be typed out either: a variable works, a sum works, and width / 2 is the middle of the canvas whatever the canvas happens to be.
There is still something these functions cannot do. One input can only say one thing, so a row of trees is a row — everything ends up at the same height. The next topic adds a second input, and then you can put a drawing anywhere at all.
3Two Inputs
Two names in a function's brackets, and their order decides which is which. The first number a call hands over goes into the first name, so one set of drawing lines can put its picture anywhere on the canvas.
Lesson — read before you start
Put two names in the brackets and you can say both:
function drawTree(x, y) {
shapeColour(BROWN);
rectangle(x - 10, y - 80, 20, 80);
shapeColour(GREEN);
circle(x, y - 130, 110);
}
Now a call hands over two numbers:
drawTree(110, 330);
The first number goes into the first name and the second into the second, so x is 110 and y is 330, and the tree stands at 110 across, 330 down.
That is the whole idea, and it has a name: the inputs are positional. It is the place in the brackets that decides where a number lands — not what the name means, and not what you meant when you typed it. Write drawTree(330, 110) and the tree goes to 330 across and 110 down, high up and off to the right. Both numbers were right and the picture is still wrong.
The same rule works on the definition. The names are yours to choose, and across and down read better than x and y for some drawings, but their order is what matters. The first name in the brackets is the one the first number lands in, whatever it happens to be called.
Everything from last topic still applies, twice over now. Every part of the body that should move needs to mention the input that moves it: a trunk written y - 80 follows the tree down, and a trunk written 250 stays at 250 while the leaves go without it. And the brackets still have to be filled. Hand over one number where the body wants two and the second name has no value at all, so the shapes are drawn nowhere and vanish without a word of complaint.
The arguments do not have to be typed out either. A variable works, a sum works, and width / 2 and height / 2 are the exact middle of the canvas whatever size the canvas happens to be.
There is one thing left that these functions cannot do. Every tree comes out the same size however cleverly you place it, so a tree meant to be far away looks like a tree standing close. The next topic hands the brackets a third number.
4More Inputs
An input does not have to be a position. Hand a function a size and one drawing gives you a whole forest with depth; hand it a colour and the same lines will paint anything you like.
Lesson — read before you start
Nothing about an input says it has to be a position. It is just a value the call hands over, and the body can use it for anything at all. Add a third name and use it as a size:
function drawTree(x, y, size) {
shapeColour(BROWN);
rectangle(x - size / 10, y - size, size / 5, size);
shapeColour(GREEN);
circle(x, y - size, size);
}
drawTree(100, 380, 150);
drawTree(330, 240, 70);
A big tree low down and a small one high up, from one set of drawing lines. That is depth, and one input bought it.
The catch is the same catch as before, one step further on. Every part of the drawing that should grow has to mention size. The trunk's width is written size / 5 and its height size, so both follow the call. Write a plain 20 in there instead and every tree gets the same trunk however big its leaves are.
Writing the parts as sums of size is what makes a drawing scale rather than stretch. A snowman's head written size / 2 is half its body at any size you ask for.
An input does not even have to be a number. A colour is a value too:
function drawTree(x, y, size, colour) {
shapeColour(BROWN);
rectangle(x - size / 10, y - size, size / 5, size);
shapeColour(colour);
circle(x, y - size, size);
}
drawTree(160, 350, 110, ORANGE);
Four inputs, and nothing new to learn. Each name is a box, the call fills them in order, and the body uses each one where it needs it.
The order still decides everything, and it bites harder now that the inputs mean different kinds of thing. Hand over a size where the down number belongs and you get a sun that fills the sky, with no error to tell you: the numbers were all fine, they just landed in the wrong boxes.
And an argument can still be worked out rather than typed. A variable works, size / 2 works, and one number in a variable can decide a whole row of sizes at once.
One thing is starting to nag. A house needs a wall, a roof and two windows, and you find yourself calling the same handful of functions in the same order over and over. Next topic, a function gets to call another function — so drawHouse can put its own windows in.
5Building a Scene
A function can call another function. Give the pieces of a picture their own names and the whole scene becomes a short list of calls — with none of the shapes in sight.
Lesson — read before you start
A function body can call other functions. So write the house once:
function drawHouse(x, y, size) {
drawWall(x, y, size);
drawRoof(x, y, size);
drawWindow(x - size / 4, y - size / 2, size / 4);
drawWindow(x + size / 4, y - size / 2, size / 4);
}
and now one line of yours draws four shapes:
drawHouse(200, 330, 160);
Three houses is three lines. drawHouse knows how a house is put together; everyFrame only says where the houses go. That split is the whole idea of this topic.
Look at what the inner calls hand over. They are not plain numbers — they are worked out from the inputs drawHouse was given. A window at x - size / 4 sits a quarter of the way left of whatever x the house was told, and it is size / 4 across, so it moves and grows with its house. Write a plain number there instead and that window stays in one place and one size no matter which house it belongs to.
The calls still run top to bottom, and now that matters more than it did. Whatever is painted first can be painted over. Call drawWindow before drawWall and the wall covers the window completely — the window is still drawn, it is just underneath. A whole scene works the same way: the sky goes first, then the ground, then the things standing on it.
Some functions need nothing at all in their brackets. drawGround always draws the same grass, so there is nothing to tell it, and the brackets stay empty in both the definition and the call.
A function does not belong to whoever called it first. drawWindow can be called by drawHouse and by drawShop, and the colour of every window in the picture is written down in exactly one place. Change that one line and they all change.
Calls can go deeper than one level. drawStreet calls drawHouse three times, and each of those calls four more, so a single line in everyFrame ends up drawing twelve shapes. The number you hand drawStreet reaches all the way down to the windows.
Everything here is drawn once and then sits still. Next topic the numbers in the brackets start changing every frame, and the whole scene comes alive.
6Functions that Move
Hand a function a number that changes every frame and the drawing moves. One set of drawing lines, two variables, and you have two things moving at different speeds — reuse and animation multiply.
Lesson — read before you start
Put the two together. The function does not change at all:
function drawFish(x, y) {
shapeColour(ORANGE);
oval(x, y, 100, 60);
triangle(x - 48, y, x - 70, y - 26, x - 70, y + 26);
shapeColour(BLACK);
circle(x + 28, y - 10, 12);
}
What changes is the number the call hands over:
var x = 60;
function everyFrame(){
backgroundColour(BLUE);
x = x + 6;
drawFish(x, 200);
}
x is 66 on the first frame, 72 on the next, and the same four lines draw the fish in a new place every time. drawFish has no idea it is part of an animation.
That is worth sitting with, because it is the whole topic. A function is just drawing lines with names for its numbers. Whether those numbers are typed out, worked out, or different on every frame is the caller's business, not the function's.
And it means two movers cost you almost nothing:
var topX = 40;
var lowX = 40;
topX = topX + 3;
lowX = lowX + 8;
drawFish(topX, 120);
drawFish(lowX, 250);
Two variables, two speeds, two fish — one set of drawing lines. Add a third and it is one more variable and one more call.
Three things to watch for. The call has to actually hand the changing number over: write drawFish(200, 200) and x can climb all it likes while the fish stands still. The moving number does not have to be a position — hand a growing number to a size input and the drawing swells instead of travelling. And a speed can be a minus number, which sends the same call the other way.
Every challenge here draws a line at the bottom showing your numbers as they change. Watch it alongside the picture: when something is not moving the way you expect, the numbers usually tell you why before the shapes do.
Notice where the working out in that last challenge happens: out here in everyFrame, not inside drawFish. Next topic a function can do that working out for you and hand the answer back, which is a different job from drawing something.
7Working Out an Answer
A function can hand a number back instead of drawing something. Work a number out in one place, give that working-out a name, and every line that needs the answer can just ask for it.
Lesson — read before you start
function halfOf(n) {
return n / 2;
}
There is nothing on the canvas when that runs. What it does is answer. Write halfOf(600) and that call becomes 300, so you can put it anywhere a number belongs:
circle(halfOf(600), 200, 120);
return is the word that hands the answer back. It means "this is my answer, and I am finished".
That gives you two kinds of function, and it is worth keeping them apart in your head and in your names. A drawing function is named for what it draws and you call it on a line of its own: drawTree(200, 320, 90). A working-out function is named for the answer it gives and you call it inside something else: drawTree(middleOf(60, 340), 320, 90).
The reason to bother is that a number worked out in one place can be read from many. Write groundLevel once and the grass, the trees and the houses can all ask it where the ground is. Change the one number it hands back and the whole scene moves together.
Two things go wrong, and both of them go wrong quietly.
If you work a number out and do nothing with it, nothing happens. A line that says middleOf(60, 340); on its own draws no post and reports no error. The answer came back and there was nobody to give it to.
And if a function has no return line at all, it still runs and still hands back nothing. Nothing is not a number, so a shape given it simply never appears. When something has vanished with no error, an empty answer is worth suspecting.
The last three challenges here animate, because the most useful thing to work out in an animation is the next number: hand a function where something is now, and let it answer with where it goes next.
Next topic the calls are given and the bodies are missing, and you write them.
8Write the Functions Yourself
The calls are given and the bodies are missing. You write the drawing lines yourself, out of the inputs the function was handed — and one line you get right draws every call at once.
Lesson — read before you start
There is nothing new to learn. A body is the drawing lines you have used since your very first sketch, with the function's inputs standing in for the numbers:
function drawPost(x) {
shapeColour(BROWN);
rectangle(x - 10, 250, 20, 70);
}
That is the whole idea. Write 200 where x goes and the post only ever stands in one place; write x and the same line puts a post wherever the call says.
Each missing line has a comment directly above it saying what belongs there. Read it as the instruction it is. When it says rectangle(across, down, wide, tall) it is telling you the shape and the order of its numbers, and when it says "at x, size above y" it is telling you to write x and y - size rather than two numbers of your own.
Four things are worth keeping in mind.
An empty body is not an error. The call still runs, it just draws nothing, so a blank line shows up as a missing part of the picture rather than as a message in the results panel.
The pen is part of a body. If a body does not set its own colour, whatever colour was set last is still loaded, and your shape comes out in it.
The order of the lines is the order things are painted. Whatever you write second is drawn on top of whatever you wrote first.
And the names in the brackets have to match the names in the body. Call them what you like, but call them the same thing in both places.
The last five challenges move, so a variable changes between frames and a call hands the new number over. That is last topic again, with the body missing as well. Then the course is done.