While drawing things on the canvas and scooting around them is nice, it gets old very fast. Instantaneously, if you’re an end user (unless you’re on a page for looking at things, in which case, no foul). On the other hand, there are far more efficient ways of rendering porn and/or amusing pictures of cats, so I’m going to go ahead and assume that we want to liven things up with some animation.
There are two kinds of animation I’m interested in right now. The first kind, that we’re going to look at today, is moving things around the screen. The other kind, that I’m still working on (largely because I’m terrible at image editing) is sprite animation; I’ll post some more information about that as soon as I’ve finished something worth seeing.
Moving an object on the screen is as simple as updating its coordinates before redrawing it. That causes it to jump to a new position on screen, which is fantastic if you’re working on a game where the only means of locomotion is teleportation, but since most of us have to deal with rather more mundane activities, what we really want is for the object to cross the intervening space. We can achieve this by repeatedly updating the position of the object in small jumps, creating the illusion of movement.
Now, we know where the object is before it starts moving, and we know where we want it to end up, but how do we determine all the points in between? And how do we make sure it moves smoothly?
Interpolators are a simple answer to both questions. Since we have two points, we can derive a line of travel; if we know the speed at which the object is supposed to travel, we can calculate where the object will be at any time after it started moving. This lets us bind the movement to a timer or a cycle which updates the position every so often.
Let’s say we have an object at 0,0, and we want it to go to 100,0 at 10 pixels per second. The line it’s going to travel is 100 pixels long in total, so it will take 10 seconds (distance/speed) to get to the end.
Let’s set it going and start a stopwatch.
Right at the start, when 0 seconds have elapsed, the distance travelled is 0.
At 5 seconds, or 0.5 of the total time, distance travelled is 50.
At 10 seconds, or 1 whole of the total time, the distance travelled is 100.
In other words, the distance travelled is
([elapsed time] / [total time]) * [full distance]
We can also calculate the x and y coordinates from the ratio of elapsed time to total time:
x = (x2 - x1) * ([elapsed time] / [total time]) y = (y2 - y1) * ([elapsed time] / [total time])
Where x1 and y1 are the coordinates of the starting point, and x2 and y2 are the coordinates of the destination. Plugging the examples above here:
At 0 seconds:
x = (100 - 0) * (0/10) = 100 * 0 = 0 y = (0 - 0) * (0/10) = 0 * 0 = 0
At 5 seconds:
x = (100 - 0) * (5/10) = 100 * 0.5 = 50 y = (0 - 0) * (0/10) = 0 * 0 = 0
At 10 seconds:
x = (100 - 0) * (10/10) = 100 * 1 = 100 y = (0 - 0) * (0/10) = 0 * 0 = 0
The linear interpolator above does it’s job well enough, but once you see it in action, you’ll notice that the rate of movement is perfectly constant across the whole length of the movement. In most cases in the physical world (you know, the one with smells and stuff) when something starts moving it will start off slow, pick up momentum, and eventually slow down to a stop.
Unless you’re in space, in which case you’ll just keep hurtling through the void until you crash into something or get sucked into a black hole.
Luckily, modelling different types of acceleration and deceleration isn’t that tricky (“it just takes a lot of tweaking or some good math skills”, he didn’t say). The interpolation above is defines a line (hence the linear); we can define a basic system of easing by changing it so that it defines a curve.
Suppose you plot the linear interpolation out on a graph: the distance travelled is a straight line based on the elapsed time (blue), and the speed is constant throughout (red, not to scale):
It’s pretty straightforward; y = x stuff. Now let’s say we change it a little so that y = x2 and we have ourselves a nice ease-in:
That gives us a nice curve, which means that the movement will start off nice and slow, and pick up speed until the end of the path. Perfect if you ever need to animate someone running face-first into a wall.
As you can see, tweaking the interpolator a little gives you control over the speed and acceleration of your moving objects. I’ve added ease-out and ease-in-out interpolators in the example, both based on the square of the time coefficient, but there’s really a cubic buttload of different functions you could use if that’s the kind of thing you dig.
Other stuff you can animate
Although I wrote this for practice with canvas, there are a bunch of different areas you could apply it to besides positioning. For example, you could use an interpolation to smoothly change the opacity or colour of an element; there’s nothing that ties this concept to the canvas element. If you’re looking to do this though, you might be better served looking into css3 transitions or jQuery animation.
No, seriously. Don’t reinvent the wheel.