Animating objects
When doing digital animation there is never need for more than one single timer.
The key is to bind properties to the objects being animation such as its position, speed (or steps), color, shape and so forth.
The logic step therefor is to create custom objects that we can collect this information and use an update function to do all the updates for us in a single step within the loop.
Example
ONLINE DEMO HERE
Lets create an object collection where we store all our objects:
var animObjects = [];
Nothing fancy about that - just an array.
A single loop
To show how simple this can get I will show the loop itself first, then dissect the object. The loop simply iterates through our collection and calls the update
method on each object:
function loop() {
/// clear canvas before redrawing all objects
ctx.clearRect(0, 0, demo.width, demo.height);
/// loop through the object collection and update each object
for(var i = 0, animObject; animObject = animObjects[i]; i++) {
animObject.update();
}
/// use this instead of setTimeout/setInterval (!)
requestAnimationFrame(loop);
}
Now, you noticed probably that we used requestAnimationFrame
(rAF) here instead of setTimeout
or setInterval
. rAF allows us to synchronize to the monitor's update frequency whereas setTimout
/setInterval
cannot. In addition rAF works more efficient than the other two which will benefit us if we need to animate a lot of stuff.
The animation object
Now lets take a look at the object, how come we only need to call update and things animate?
As we saw earlier we create a animated circle object simply by calling:
var animObject = new animCircle(context, x, y, radius, color, stepX, stepY);
This allows us to set which context we want to use (in case we use several layers of canvas), the start position, color and number of steps per frame. Note that these properties can be changed during the animation (e.g. change radius and color).
The object itself looks like this -
function animCircle(ctx, x, y, r, color, stepX, stepY) {
/// keep a reference to 'this' context for external calls
var me = this;
/// make the parameters public so we can alter them
this.x = x;
this.y = y;
this.radius = r;
this.color = color;
this.stepX = stepX;
this.stepY = stepY;
/// this will update the object by incrementing x and y
this.update = function() {
me.x += me.stepX;
me.y += me.stepY;
/// additional updates can be inserted here
render();
}
/// and this takes care of drawing the object with current settings
function render() {
ctx.beginPath();
ctx.arc(me.x, me.y, me.radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = me.color;
ctx.fill();
}
return this;
}
That's all there is to it!
The objects update()
method will do all the calculations for us as well as call the internal render()
method.
You can create many of these objects at various positions and speeds and animate all of them from a single loop.
I only created an object for the circle to keep things simple. You should be able to create an object for rectangle and what have you by using this as a base. You can of course extent the object to keep track of other things as well such as stroke color, angles and so forth.
I also made the objects bounce off the canvas' edges for the sake of demo. Please adjust as needed.