visuco
Start course

Interaction

The sketch stops being a film and becomes a thing you can use. Code that runs when something happens: a click, a moving mouse, a key going down and coming back up.

variablesinteraction

1Something Happens

Some code runs because time passed. Other code runs because a person did something. This topic is the difference: a block called whenMouseClicked, and a variable that remembers what it changed.

Lesson — read before you start
Everything you have written up to now has been inside everyFrame, and everyFrame runs because time passes. It runs again, and again, about twelve times a second, whether anyone is there or not.

This topic is about a different kind of block.

function whenMouseClicked(){
lampColour = YELLOW;
}

That block does not run every frame. It does not run at all until somebody clicks on the picture, and then it runs once, top to bottom, and stops again. Click a second time and it runs a second time.

The name is the whole of it. A block called whenMouseClicked runs when the mouse is clicked, in the same way that a block called everyFrame runs every frame. You do not call it yourself and you never say its name anywhere else.

There is one rule that matters more than any other here, and it is easy to get wrong. Do not draw inside the handler. A shape drawn there is thrown away before anyone sees it. What the handler is for is changing a variable:

var lampColour = GREY;

function whenMouseClicked(){
lampColour = YELLOW;
}

function everyFrame(){
shapeColour(lampColour);
circle(200, 180, 160);
}

The click changes the box. everyFrame reads the box and draws. And because the box keeps its new value, the lamp stays yellow for the rest of the run — the click happened once, but you can see that it happened for as long as you like.

Two things about these pages. The picture is live from the moment it loads, so you can click on it yourself and watch; nothing is marked until you press Run. And along the scrub bar there is a small dot at each frame where a click is scripted to happen, with a label when it fires. Step one frame at a time across that dot and you will see the exact frame the picture changes.

A click also knows where it happened. That is the next topic.

2Where Did I Click?

A click carries the place it happened, in mouseX and mouseY. This topic reads those two numbers inside the handler, keeps them, and draws from them — jumping a shape to the click, hanging one above it, sizing one by it.

Lesson — read before you start
A click happens somewhere. The sketch can find out where, because two values are waiting to be read:

mouseX is how far across the click was
mouseY is how far down it was

Both are ordinary numbers, so they can go anywhere a number can go.

function whenMouseClicked(){
x = mouseX;
y = mouseY;
}

That is the whole idea. Read them inside the handler, keep them in your own variables, and let everyFrame draw from those variables as it always has.

They are numbers, which means you can do arithmetic on them. All of these are fine:

x = mouseX + 60;
y = mouseY - 90;
x = width - mouseX;
howBig = mouseY;

The last one is worth a second look. mouseY is a number somewhere between 0 and 400, and so is a size, so a click low down can make a big shape and a click high up a small one. Nothing says the click has to move anything.

There is one thing to be careful about, and it catches people. When two lines both run on the same click, the order matters:

oldX = x;
x = mouseX;

Keep the old value first, then take the new one. Write those two the other way round and the old value is gone before you saved it, so both variables end up holding the same number and the two shapes land on top of each other.

The readout along the bottom of every picture in this course shows mouseX and mouseY the whole time, so you can always check a number you have worked out against the one it came from. And the little dot on the scrub bar marks the frame each scripted click happens on — step across it one frame at a time.

In the last challenge there are no clicks at all. That is because mouseX can be read from inside everyFrame too, and there it means something slightly different: where the mouse is right now. Following the mouse without clicking is the next topic.

3Following the Mouse

The mouse has a place all the time, not only when it is clicked. Read it every frame and a shape follows the pointer; read where it was a moment ago and you can talk about movement instead of position.

Lesson — read before you start
A click is a moment. The mouse is somewhere all the time.

That is the whole of this topic. mouseX and mouseY are not only readable inside a click handler — they can be read anywhere, and read from inside everyFrame they mean where the pointer is right now:

function everyFrame(){
circle(mouseX, mouseY, 70);
}

No handler, no click, and the shape follows the pointer around the canvas. Move your mouse over the picture and watch.

There is also a handler for movement:

function whenMouseMoved(){
x = mouseX;
y = mouseY;
}

whenMouseMoved runs every time the pointer moves, whether a button is down or not. It can end up drawing the same picture as reading mouseX every frame — the difference is when the line runs, not what it draws. Reading every frame keeps working even when the mouse is perfectly still; the handler only runs when something actually moved.

Two more values arrive here:

lastMouseX is where the pointer was one move ago
lastMouseY is the same for down

They let you talk about movement rather than position. A ghost drawn at lastMouseX lags behind the real one. A line from lastMouseX, lastMouseY to mouseX, mouseY shows the hop the mouse just made. And distance(mouseX, mouseY, lastMouseX, lastMouseY) is how far that hop was, which is a number you can make a shape out of.

One thing to watch with that last one. If the mouse is not moving, the distance is 0, and a shape with a size of 0 is nothing at all. Add a base to it:

circle(200, 180, 30 + distance(mouseX, mouseY, lastMouseX, lastMouseY));

Following does not have to be exact. This line moves a fifth of the way towards the pointer each frame, and the result glides rather than jumps:

x = x + (mouseX - x) / 5;

Divide by a bigger number and it gets lazier. Two shapes with different numbers spread out when the mouse moves and gather again when it stops.

The last challenge is about the button rather than the pointer. mouseIsPressed is true while it is held down and false the rest of the time, so a question about it can turn the following on and off. Taking the button apart — the moment it goes down, the moment it comes up, and the whole click — is the next topic.

4Press and Let Go

A click is really two moments with a stretch in between: the button going down, the button coming back up, and the whole time it is held. Three handlers, and one value that stays true throughout.

Lesson — read before you start
A click is not one thing. Watch your own hand: the button goes down, and some time later it comes back up. Those are two separate moments, and there is a handler for each.

function whenMousePressed(){
}

function whenMouseReleased(){
}

whenMousePressed runs the instant the button goes down. whenMouseReleased runs the instant it comes back up. Nothing at all happens in between — no handler runs while you are holding.

But something is still true in between, and that is different from something happening:

mouseIsPressed

That is true for every frame the button is down and false for every frame it is up. It is a stretch, not a moment, so you ask about it in everyFrame:

if (mouseIsPressed == true) {
howBig = howBig + 8;
}

Hold the button and the ball grows for as long as you hold. Let go and it stops where it is. A handler could not do that, because a handler runs once and this has to happen on every frame.

The readout at the bottom of these pictures shows mouseIsPressed, so you can watch it flip on and off as the markers on the scrub bar go past.

Now the third handler, the one you already know:

function whenMouseClicked(){
}

A click means the button went down and came back up in the same place. So all three run, one after another, in this order: pressed, released, clicked. If all three change the same variable, the one that runs last is the one you see.

And the useful half of that: if the button goes down in one place and comes up somewhere else, that is a drag, not a click. whenMousePressed runs. whenMouseReleased runs. whenMouseClicked does not.

Both moments have a place, just as a click does. mouseX inside whenMousePressed is where the button went down; mouseX inside whenMouseReleased is where it came up. Keep both and you can draw the whole gesture — which is exactly how dragging a selection box works.

The last challenge here is a keyboard one. A key going down is the same shape of idea as a button going down, and the whole of the next topic is about it.

5Keys

The keyboard is another kind of event, and it arrives with a question attached: which key was it. Arrows that steer, letters that choose, and a space bar that puts everything back.

Lesson — read before you start
The keyboard sends events too, and the block for them is whenKeyPressed:

function whenKeyPressed(){
x = x + 70;
}

That runs when any key at all goes down. Which is fine until you want the arrows to do different things, and then you need to know which key it was.

keyCode holds a number for the key that went down, and the keys without letters have names you can compare against:

LEFT RIGHT UP DOWN SPACE ENTER

So:

function whenKeyPressed(){
if (keyCode == RIGHT) {
x = x + 80;
}
}

Now only the right arrow moves anything. The readout at the bottom of the picture shows the number keyCode is holding, so you can see for yourself that RIGHT is 39 and SPACE is 32. The name is just a friendlier way of writing the number.

Line the questions up with else if and only the first true one wins, which is what you want here because a key cannot be two keys at once:

if (keyCode == RIGHT) {
x = x + 60;
} else if (keyCode == LEFT) {
x = x - 60;
} else if (keyCode == UP) {
y = y - 80;
} else if (keyCode == DOWN) {
y = y + 80;
}

Remember that up the screen is a smaller number, so UP takes away.

Letter keys are different. They have a character, and key holds it:

if (key == "r") {
lampColour = RED;
}

Note the quote marks. key holds a word one letter long, not a number, so it is compared against a word.

One thing worth doing early. A shape that moves 100 for every press will walk off the canvas after four of them, and limit is how you stop that:

x = limit(x + 100, 40, 340);

Keep it between 40 and 340 whatever happens.

The keys can drive anything, not only positions — a size, a colour, a speed. A key that sets a speed is worth a look: one press, and the shape keeps going until another press changes its mind, because everyFrame is doing the moving.

The last challenge has a second handler in it. A keystroke has two ends like a click does, and whenKeyReleased runs at the far one. That is the next topic.

6Key Up, Key Down

Holding a key is not the same as pressing it. Split a keystroke into its two ends and a stretch appears in the middle — which is what steering, charging and firing are all made of.

Lesson — read before you start
In the last topic every key press was a tap: down and up in the same instant. Hold a key instead and there is a stretch in the middle, and that stretch is what this topic is about.

Two handlers mark the ends:

function whenKeyPressed(){
speed = 8;
}

function whenKeyReleased(){
speed = 0;
}

And one value is true the whole way through:

keyIsPressed

Ask about that in everyFrame, not in a handler. A handler runs once, at a moment; a stretch has to be asked about on every frame, because that is what "the whole time" means.

if (keyIsPressed == true) {
x = limit(x + 9, 40, 360);
}

Hold the key and the ball moves on every frame — smoothly, rather than in jumps. That is how everything you have ever steered actually works, and it is the first thing in this course that feels properly like a game.

The other half of holding is charging:

if (keyIsPressed == true) {
charge = limit(charge + 14, 0, 300);
}

The longer the hold, the bigger the number. Then the release reads it:

function whenKeyReleased(){
speed = charge / 8;
charge = 0;
}

Hold longer, shoot further. Two lines.

There is a challenge here that is worth staring at. It is the charge meter again, driven by taps instead of holds, and the meter never moves at all — because a tap presses and lets go in the same instant, so there is no stretch to measure. Nothing is broken. There is simply nothing there.

keyIsPressed says a key is down. keyCode says which one. Together they say a particular key is being held:

if (keyIsPressed == true) {
if (keyCode == RIGHT) {
x = limit(x + 10, 40, 360);
}
}

The readout at the bottom shows both, so you can watch held go true on the down marker and false on the up one.

The last challenge goes back to the mouse and asks a different kind of question: how far the pointer is from a shape. Answering that properly — did I actually hit the thing — is the next topic.

7Clicking on Things

Did I hit it. A round thing is one comparison against distance, a box is four comparisons joined with &&, and once a sketch can answer the question it can have buttons and things you drag.

Lesson — read before you start
Every click so far has counted, wherever it landed. This topic asks a harder question: did the click land on that particular thing.

For anything round, distance answers it:

if (distance(mouseX, mouseY, 200, 180) < 70) {
ballColour = YELLOW;
}

distance measures between two points — here, from the click to the middle of the ball. If it is less than the ball's radius, the click was inside.

Watch the number you compare against. A circle is drawn with its width:

circle(200, 180, 140);

so the distance from the middle to the edge is half of that, 70. Comparing against 140 makes a ball that lights up when you click a whole radius outside it, which looks like a bug and is really arithmetic. When the size is in a variable, write it out:

if (distance(mouseX, mouseY, 200, 180) < howBig / 2) {

A box is a different question, because a box is not round. Being inside it means four things are all true at once, and && joins them:

if (mouseX > 100 && mouseX < 300 && mouseY > 120 && mouseY < 260) {

Right of the left edge, left of the right edge, below the top, above the bottom. Use the same numbers the rectangle is drawn with and the test cannot drift away from the picture.

That is a button. Everything a button does, it does with those four comparisons.

Now the thing all of this was for. Dragging is three moments and one variable:

function whenMousePressed(){
if (distance(mouseX, mouseY, x, y) < 50) {
held = 1;
}
}

function whenMouseDragged(){
if (held == 1) {
x = mouseX;
y = mouseY;
}
}

function whenMouseReleased(){
held = 0;
}

The press asks whether you grabbed it. The drag follows the pointer, but only if you did. The release lets go. Take the held question out of the middle one and dragging anywhere on the canvas teleports the ball, which is worth trying once to see.

Some of the clicks scripted into these challenges are aimed to miss on purpose. The label on the scrub bar says so when one fires, and a hit test that is too generous will light up when it should not.

8Make It Interactive Yourself

No more filling in numbers. The missing part is the whole line now, with a comment above it saying what it has to do — a handler body, a hit test, a drag, and finally a sketch driven by the mouse and the keyboard at once.

Lesson — read before you start
The scaffolding comes away here. From now on the missing part is a whole line, and the comment directly above the gap says what that line has to do:

// set x to mouseX

You write the line. Everything you need has been in the last seven topics.

A few reminders, because they are the things people get wrong when nothing is filled in for them.

A handler changes a variable. It never draws. Whatever a handler draws is thrown away before anyone sees it, so put the change in a variable and let everyFrame draw from it.

Every line ends with a semicolon and every name is spelled exactly as it is elsewhere in the sketch. mouseX has a capital X. lampColour is spelled the way it is declared at the top.

A question about a round thing measures distance to its middle and compares against half its width:

distance(mouseX, mouseY, 200, 180) < 70

A question about a box is four comparisons joined with &&, using the same numbers the rectangle is drawn with:

mouseX > 120 && mouseX < 280 && mouseY > 140 && mouseY < 240

A stretch — the button being held, a key being held — is asked about in everyFrame with mouseIsPressed or keyIsPressed. A moment — the button going down, a key coming up — gets a handler.

There is one handler here you have not used yet. whenKeyTyped runs when a character key is typed, and key holds the character. It works exactly like whenKeyPressed and is in the reference drawer with the rest of them.

If a line does not work, read the message in the results panel. It gives the line number for a misspelled name, and the picture beside yours is what you are aiming at — step through it a frame at a time and find the frame where the two stop agreeing.

9Code it yourself

An empty editor and a row of blocks above it, including one for every handler. No holes to fill and no lines to copy — the description says what the sketch does and what the mouse and keyboard do to it.

Lesson — read before you start
Same as the last topic, with the page left blank.

There is no starter here. The editor opens empty and a row of blocks sits above it. Click one and it drops the shape of the code in at the cursor, already indented, with the caret on the line you have to fill:

function whenMouseClicked(){

}

The When row has all eight handlers in it. The Structure row has everyFrame, if and else. Drawing and Style have the shapes and the colours. Nothing in this topic needs a word that is not on one of those buttons or in the reference drawer.

The description is the whole instruction. It tells you the background, every shape with its place and its size, and what each piece of input does. Every number you need is in it and nothing that is not — so read it as a list and work down.

Two things worth having in your head before you start.

A handler changes a variable. It never draws. Put the variable at the top with var, change it in the handler, and draw from it in everyFrame:

var lampColour = GREY;

function whenMouseClicked(){
lampColour = YELLOW;
}

function everyFrame(){
backgroundColour(BLACK);
shapeColour(lampColour);
circle(200, 180, 160);
}

And a moment is not a stretch. Something that happens once — a click, a key going down — gets a handler. Something that is true for a while — the button being held, a key being held — is asked about in everyFrame with mouseIsPressed or keyIsPressed.

There is no readout along the bottom of these pictures. Turn the grid on if you want to check where a shape has actually landed. The picture is live from the moment it loads, so try your sketch with your own mouse and keyboard before you press Run.

Report this course