We have already seen how to animate on Canvas in one of our last tutorials. That was quite straight forward as we were using Canvas drawing straight out of the box. Here we will use our newly learnt tools(loading and drawing bitmap image in canvas) to make an animation.
The source files are here for you to download and play.
The concept is the same though as in re-drawing in the canvas at a regular interval, but instead of drawing with drawing API, we will be drawing image.
First of all lets understand what a sprite sheet is? The sprite sheet is an image! Just an image? Yes, its just an image file. In that image file, we should have almost all the images needed for our purpose. That means, one image file consisting of all the images required in a project. Why its necessary? Good question. The reason being we have just one call to the server and all our image data is loaded. The next reason is to update the image data. Suppose we want to update the graphics all at once, we just have to update one image file.
If you are going through the image file in our source, the image file has 12 different images of a character. All we are going to do is, cycle over each character over a time. That we can do with a “setInterval()” javascript function.
Lets see the javascript code first and then we will go learn it.
$.ready()
{
//------------- 1. defining the variables and functions----------------
var resetCanvas,resetContext,
canvas_1,context_1,
image_data,photo,loadPhoto,imageLoaded,timer,onTimer,counter,animate;
//------------- 2. configuring ---------------------------------------
//get the canvas and context
canvas_1=$('#board_one').get(0);
context_1=canvas_1.getContext('2d');
counter=1;
//---------------functions----------------------------------
//resetting the width and height, it automatically resets the canvas
//clear the board, quick and dirty, its a HACK!!
resetCanvas = function (canvasRef){
canvasRef.width=canvasRef.width;
canvasRef.height=canvasRef.height;
};
//clear the board
resetContext=function(canvasRef,contextRef){
contextRef.clearRect(0,0,canvasRef.width,canvasRef.height);
};
imageLoaded=function(evt)
{
var originalPic=evt.target;
animate();
};
loadPhoto=function(path)
{
photo.src=path;
};
animate=function(){
timer=setInterval(onTimer,150);
};
onTimer=function(){
resetContext(canvas_1,context_1);
//draw again
if(counter>=12)
{
counter=0;
}
context_1.drawImage(photo, 97*counter, 0, 97, 95, 230, 110, 97, 95);
counter++;
//clearInterval(timer);//incase we need to stop the animation
};
//----------------3. using-----------------------------
image_data=context_1.createImageData(canvas_1.width,canvas_1.height);
photo=new Image();
photo.onload=imageLoaded;
loadPhoto('images/walkSheet.png');
};
In the beginning we have just defined the variables, then populating them with the required values and scripts. Lastly we are calling our methods and using these variables.
In the beginning we get our canvas and its context. Intitialised the “counter” to 1 as we have 12 different positions of the image, we will be needing a counter to move to next position. So once these properties are populated, we have created some functions, which we use. Then moving on to the actions, firstly there is an “image_data” object, I have created, but not used. That is just to show we can create an image data object from the canvas, which is used to pixel manipulation. So the first thingon making our animation is making an Image object with
photo=new Image();
Then we have to provide an event handler for its image load event, that is done with the code below.
photo.onload=imageLoaded;
If you remember we have already created the “imageLoaded” function, which looks as below.
imageLoaded=function(evt)
{
var originalPic=evt.target; //just for the shake of understanding
animate();
};
Here the first the “originalPic” variable is defined just to know that we can get the image from the event object as “event.target” . So all in all this “imageLoaded” function actually initialises our animation by calling “animate()”.
animate=function(){
timer=setInterval(onTimer,150);
};
And “animate()” function actually intialises the timer for animation and calls “onTimer” function repeatedly at each 150 milliseconds.
onTimer=function(){
resetContext(canvas_1,context_1);
//draw again
if(counter>=12)
{
counter=0;
}
context_1.drawImage(photo, 97*counter, 0, 97, 95, 230, 110, 97, 95);
counter++;
//clearInterval(timer);
};
This is the place, where all the action is happening. First we have to clear our canvas, that is being done on the first line of this function. Next we check, whether the “counter” is more than 12, if it is then reset it to 0. Thats for we have just 12 different images. Now the line which actually draws our animation is
context_1.drawImage(photo, 97*counter, 0, 97, 95, 230, 110, 97, 95);
This is actually drawing part of the sprite sheet to a particular are in the canvas. Its like copying a portion from the sprite sheet and pasting it in the Canvas. On the next timer event (ie; after another 150 milliseconds, it will copy another portion and paste it in the same location.) we take another portion from the sprite sheet and paste it in the same area of canvas. Since we are clearing the canvas and re-drawing it over a period of time, it seems as if the character is animating! The time of 150 milliseconds is just a guess, we can lower it to see the jerky animation or higher it to see the character move faster. The other values as 97,95 are the width and height of each image in pixels, so that would be different for different sprite sheets.
The last line increments the counter by one.
Now we have a nice looking animation in our HTML Canvas.
Things to not here is, I struggled for sometime to see this working, for I was providing wrong parameter values (97,95 seemed perfect). So if your animation is not visible, first see if the parameter values are correct. Even one pixel higher than the actual image height or width will make the whole thing invisible. Though lower values work fine.
Happy coding.