In these notes you will learn:

- How to make an object move to clicked point.
- How to implement easing.

In these notes we will see how to make an object move to a point on the screen where the user clicks.

Lets write a demo program that makes a ball move smoothly to a point the user clicks. To keep things simple, we won’t worry about dragging or collisions with the screen edges.

One subtle point to consider is what to do when the user clicks on a
new point *while* the ball is moving. Should the ball start moving to
the new point, or should it ignore the click and continue
uninterrupted? There is no right or wrong answer: it depends on what
you want your program to do. We’ll assume the program should ignore
clicks while the ball is moving.

Here’s is a first program that lets the user move a ball by clicking on points on the screen:

```
float x, y;
float diam;
float dx, dy;
// (goalX, goalY) is the new point the ball is moving to
float goalX;
float goalY;
void setup() {
size(500, 500);
smooth();
x = 250;
y = 250;
dx = 0;
dy = 0;
diam = 60;
}
void draw() {
background(255);
noStroke();
// draw the circle
fill(255, 0, 0);
ellipse(x, y, diam, diam);
// draw the goal point
fill(0, 255, 0);
ellipse(goalX, goalY, 10, 10);
// move the circle
x += dx;
y += dy;
// stop moving when the center of the ball is
// less than two pixels away from the goal point
if (dist(x, y, goalX, goalY) <= 2) {
dx = 0;
dy = 0;
}
}
void mousePressed() {
// the ball is not moving if both dx and dy are 0
if (dx == 0 && dy == 0) {
goalX = mouseX;
goalY = mouseY;
// d is the distance the ball must travel to reach the goal point.
// To move 1 pixel in the direction of (goalX, goalY), move
// (goalX - x) / d pixels along the x-axis, and (goalY - y) / d
// pixels along the y-axis.
float d = dist(x, y, goalX, goalY);
dx = 2 * (goalX - x) / d;
dy = 2 * (goalY - y) / d;
println("mousePressed() called:");
println(" dx = " + dx + ", dy = " + dy);
println(" goalX = " + goalX + ", goalY = " + goalY);
}
}
```

Notice a couple of things:

In the

`draw()`function we use an if-statement to check if the ball is less than 2*pixel*s away from the goal point. If it is, then we stop it by setting its velocity to 0.In the

`mousePressed()`function we use an if-statement to check if the ball is not moving, i.e. if both`dx`and`dy`are 0. If the ball is not moving, then a new goal point is set and`dx`and`dy`are initialized.Also in

`mousePressed`, we set`dx`and`dy`like this:float d = dist(x, y, goalX, goalY); dx = 2 * (goalX - x) / d; dy = 2 * (goalY - y) / d;

`d`is the distance the ball must travel to get to the goal point. It turns out that if you move`(goalX - x) / d`in the x-direction and`(goalY - y) / d`in the y-direction, then you are moving towards (`goalX`,`goalY`) at a rate of 1 pixel per call to`draw()`(the justification for this fact relies on the geometry of similar triangles). To move at a rate of 2 pixels per call to`draw()`, multiply both`(goalX - x) / d`and`(goalY - y) / d`by 2 as we’ve done in the code.

You may have noticed in the above program that the ball always moves at the same constant velocity. While this might be what you want, real-life objects rarely start and stop instantly. Instead, there is a short period of acceleration when they start, and a short period of deceleration when they stop.

Lets add this behavior to our program. As the ball gets closer and closer to the goal point, it should move slower and slower, eventually stopping completely.

So instead of moving at a constant speed, the ball *decelerates* as it gets
closer to its goal.

This trick of using the distance from an object to control an object’s speed
is known as *easing*.

Here’s a version of the above program that implements easing when the ball moves towards the target (there is no easing when the ball starts!):

```
float x, y; /// center of the ball
float diam;
float dx, dy; // ball's velocity
// (goalX, goalY) is the new point the ball is moving to
float goalX, goalY;
float maxSpeed; // fasted speed the ball can go
float easingLimit; // distance from goal when easing starts
void setup() {
size(500, 500);
smooth();
// the ball starts in the center of the screen
x = 250;
y = 250;
diam = 60;
dx = 0;
dy = 0;
maxSpeed = 4;
easingLimit = 100;
}
void draw() {
background(255);
noStroke();
//
// draw the circle
//
fill(255, 0, 0);
ellipse(x, y, diam, diam);
//
// dx != 0 || dy != 0 is true just when the ball is moving
//
// || means "or" and != means "not equal to"
//
if (dx != 0 || dy != 0) {
// draw the goal point the ball is moving towards;
// the gray "halo" shows the easing limit where the
// ball's velocity starts to decrease
fill(0, 255, 0);
ellipse(goalX, goalY, 5, 5);
noFill();
stroke(200);
ellipse(goalX, goalY, easingLimit, easingLimit);
}
// move the ball
x += dx;
y += dy;
// if the distance from the ball's center to the goal is less
// than one pixel, stop the ball; or, if the ball is within
// the easing limit of the goal, then set its speed to be
// proportional to the distance from the goal
float d = dist(x, y, goalX, goalY);
if (d <= 2) {
dx = 0;
dy = 0;
x = goalX;
y = goalY;
} else if (d < easingLimit) {
float rate = (d / easingLimit) * maxSpeed;
dx = rate * (goalX - x) / d;
dy = rate * (goalY - y) / d;
}
}
void mousePressed() {
if (dx == 0 && dy == 0) {
goalX = mouseX;
goalY = mouseY;
float d = dist(x, y, mouseX, mouseY);
dx = maxSpeed * (goalX - x) / d;
dy = maxSpeed * (goalY - y) / d;
}
}
```

Note the following:

- Two new variables have been added::
float maxSpeed; float easingLimit;

`maxSpeed`is the fastest the ball can move when going to a new point. When the distance between the ball and goal point is less than`easingLimit`, we set the ball’s velocity to be proportional to its distance from the goal.Note that you can get a wide variety of behaviors just by changing the values of

`maxSpeed`and`easingLimit`.In

`draw()`, we now need to check if the ball is within the target’s easing limit:float d = dist(x, y, goalX, goalY); if (d <= 2) { dx = 0; dy = 0; x = goalX; y = goalY; } else if (d < easingLimit) { float rate = (d / easingLimit) * maxSpeed; dx = rate * (goalX - x) / d; dy = rate * (goalY - y) / d; }

First,

`d`, which is the distance between the ball and the goal point, is calculated. We do this because we use the distance four times in the lines that follow, and so it is more efficient — and easier to read — if we calculate it once at the start.Next comes an

*if-else-if statement*:if (d <= 2) { dx = 0; dy = 0; x = goalX; y = goalY; } else if (d < easingLimit) { float rate = (d / easingLimit) * maxSpeed; dx = rate * (goalX - x) / d; dy = rate * (goalY - y) / d; }

First we check if the value of

`d`is less than 2. If so, we stop the ball by setting`dx`and`dy`to 0. Since it’s possible that the ball might not end up centered exactly on the goal point, we then explicitly center at (`goalX`,`goalY`).Next comes the

`else if`part where we check to see if the ball is within the easing limit. If it is, then we set the speed to be proportional to the ball’s distance from the goal. We need to do a bit of arithmetic here to get the correct speed:float rate = (d / easingLimit) * maxSpeed;

Since

`d < easingLimit`when this statement is executed, the expression`d / easingLimit`is less than 1. When we multiply that by`maxSpeed`, the result is a speed less than`maxSpeed`that is proportional to`d`. In other words,`speed`decreases as the ball gets closer to the goal.Note

We are playing fast and loose with the equations for speed and acceleration because all that matters to us is that the resulting motion

*looks*good. We are not worried about a precise simulation of reality. If we were, we would need to be much more careful to use the proper physical equations.Finally, we add a small target and “halo” to help visualize the goal point and the easing limit:

if (dx != 0 && dy != 0) { fill(0, 255, 0); ellipse(goalX, goalY, 5, 5); noFill(); stroke(0, 255, 0); ellipse(goalX, goalY, easingLimit, easingLimit); // ... } This provides an easy way to visually check if the program is working as expected.

Explaining the basic technique of

*easing*.Assuming

`easingLimit`has the same value as in the program in the notes, do the following two code fragments do the same thing?// // fragment 1 (else if) // if (d < 1) { dx = 0; dy = 0; } else if (d < easingLimit) { speed = d * maxSpeed / easingLimit; } // // fragment 2 (if) // if (d < 1) { dx = 0; dy = 0; } if (d < easingLimit) { speed = d * maxSpeed / easingLimit; }

Explain your answer carefully!

What values of

`easingLimit`make the two code fragments in the previous question behave*differently*?Assuming

`easingLimit`has the same value as in the program in the notes, do the following two code fragments do the same thing?// // fragment 1 // if (d < 1) { dx = 0; dy = 0; } else if (d < easingLimit) { speed = d * maxSpeed / easingLimit; } // // fragment 2 // if (d < easingLimit) { speed = d * maxSpeed / easingLimit; } else if (d < 1) { dx = 0; dy = 0; }

Explain your answer carefully!

Explain in English what the boolean expression

`dx != 0 && dy != 0`tests for. Is it equivalent to the expression`!(dx == 0 && dy == 0)`?

There’s a bug hiding in

*the first program*.You can see it if you change the speed of the ball to be 3 in

`mousePressed`:dx = 3 * (goalX - x) / d; dy = 3 * (goalY - y) / d;

When you try the program you should see that sometimes the ball flies past the green dot without stopping.

Figure out what the problem is and fix it.

Modify

*the easing program*to add easing to the*beginning*of the ball’s journey, i.e. make the ball’s velocity start out slow and then gradually increase until it is far enough away from where it started.Modify

*the easing program*so that if the user clicks on a new point while the ball is moving, then it will immediately start moving towards this new point.