To understand simple easing, imagine you have an object over here and you want to move it over there.
Since you’re creating the ”illusion of motion,” you want to move it there gradually, over several frames. You could simply find the angle between the two, set a speed, use some trigonometry to work out the
vx
andvy
, and set it in motion. Then you could check the distance to the target on each frame (using the Pythagorean Theorem, as described in Chapter 3), and when it arrives there, stop it. That approach might work in some situations, but if you’re trying to make something look like it’s moving naturally, it won’t do.The problem is that your object would move along at a fixed velocity, reach its target, and stop dead. If you’re talking about some object moving along and hitting a brick wall, yes, it might be sort of like that. But when you’re moving an object to a target, this generally implies that you know where this target is, and are deliberately moving the object into place there. In such a case, the motion will start out fairly fast, and then slow down as it gets closer to the target. In other words, its velocity is going to be proportional to the distance to the target.
Let’s take an example: You’re driving home. When you are a few miles away, you’re moving at the speed limit. When you pull off the highway and into your neighborhood, you’re moving a bit slower. Once you’re on your own street, a block or two away, you’ll move much slower. As you approach your driveway, you’re down to a few miles per hour. When you reach the last few feet of the driveway, you’re moving a lot slower than when you pulled into the driveway. And inches before you stop, you’re moving at a fraction of that speed.
If you take the time to look, you’ll see this behavior manifests itself even in small things like closing a drawer or door. You start out fast and gradually slow down. The next time you go to close a door, make an effort to follow through with the same speed you started with; just be prepared to explain to anyone nearby why you’re slamming doors. When you use easing to move an object into position, it automatically takes
171
on a very natural appearance. One of the coolest things is that simple easing is actually very easy to do. In fact, it’s probably easier than figuring out the angle, thevx
, and thevy
, and moving at a fixed speed.Here is the strategy for easing:
Decide on a number for your proportional motion. This will be a fraction of 1.
Determine your target.
Calculate the distance from the object to the target.
Multiply the distance by the fraction. This is your velocity.
Add the velocity value to the current position.
Repeat steps 3 through 5 until the object is at the target.
Distance
Moves a fraction of the distance
New distance
Moves a fraction of the new distance
Target
Figure 8-1. Basic easing
Let’s go through these steps one at a time, and see how to program them. Don’t worry about where to put the code yet, you're just seeing how the code looks and what it means.
First, decide on a fraction to represent the proportion. As I said, the velocity will be proportional to the motion. Specifically, this means that the velocity will be a fraction of the distance, something between 0 and 1. The closer it is to 1, the quicker the object will move. The closer it is to 0, the slower it will move, but be careful, because too low a value and you'll be waiting a very long time for the object to reach its target.
For starters, choose something like 0.05, and we'll call this variable
easing
. So you can begin with the following code:var easing = 0.05;
Next, determine your target; this is a simple x, y position. You can make it the center of the canvas element for lack of anything better:
172
var targetX = canvas.width / 2, targetY = canvas.height / 2;
Then calculate the distance to the target. Assuming you have an object named
ball
, you just subtract the ball’s x and y from the target x and y:var dx = targetX – ball.x, dy = targetY - ball.y;
Your velocity is then the distance times the fraction:
var vx = dx * easing, vy = dy * easing;
ball.x += vx;
ball.y += vy;
These last few steps need to be repeated, so those will go in your
drawFrame
function. Let’s take a closer look at those steps, as they can be largely simplified:var dx = targetX – ball.x, dy = targetY – ball.y, vx = dx * easing, vy = dy * easing;
ball.x += vx;
ball.y += vy;
You can condense the first two lines into the second two pretty easily:
var vx = (targetX - ball.x) * easing, vy = (targetY - ball.y) * easing;
ball.x += vx;
ball.y += vy;
Or, you can consolidate it even further:
ball.x += (targetX - ball.x) * easing;
ball.y += (targetY - ball.y) * easing;
As you explore easing, you might want to use the more verbose descriptions to make it clearer. But once you understand how it works, the third version communicates perfectly. We’ll stick with the second version here, just to reinforce the idea that you’re dealing with velocity.
Now, let’s see it in action. You’ll need the
Ball
class you’ve been using all along, and here’s the example,01-easing-1.html
:<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Easing 1</title>
<link rel="stylesheet" href="style.css">
173
</head><body>
<canvas id="canvas" width="400" height="400"></canvas>
<script src="utils.js"></script>
<script src="ball.js"></script>
<script>
window.onload = function () {
var canvas = document.getElementById('canvas'), context = canvas.getContext('2d'),
window.requestAnimationFrame(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
var vx = (targetX - ball.x) * easing,
Play around with the
easing
variable to see how it affects the resulting motion.The next thing you might want to do is drag the ball around and then have it ease back to its target. This is similar to the drag-and-drop technique you set up in Chapter 7. Here, you start dragging the ball when it is pressed with the mouse. The
drawFrame
function checks if the ball is being dragged, and if so, performs the easing calculations. Here’s the document,02-easing-2.html
:<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Easing 2</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<script src="utils.js"></script>
<script src="ball.js"></script>
<script>
window.onload = function () {
var canvas = document.getElementById('canvas'), context = canvas.getContext('2d'),
mouse = utils.captureMouse(canvas),
s
174
canvas.addEventListener('mousedown', function () {
if (utils.containsPoint(ball.getBounds(), mouse.x, mouse.y)) { isMouseDown = true;
canvas.addEventListener('mouseup', onMouseUp, false);
canvas.addEventListener('mousemove', onMouseMove, false);
} }, false);
function onMouseUp () { isMouseDown = false;
canvas.removeEventListener('mouseup', onMouseUp, false);
canvas.removeEventListener('mousemove', onMouseMove, false);
}
window.requestAnimationFrame(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
if (!isMouseDown) {
If you are calculating simple easing to a single target, eventually you’ll get to the point where the object is at the target and the purpose of the easing has been achieved. But, in the examples so far, the easing code continues to execute, even though the object isn’t visibly moving anymore. If you are just easing to that point and leaving the object there, continuing to run the easing code is a waste of system resources. If you’ve reached your goal, you might as well stop trying. At first glance, this would be as simple as checking whether the object is at its target and turning off the animation loop, like so:
Download from Wow! eBook <www.wowebook.com>