Wednesday, March 7, 2012

HTML 5 Canvas Sprite Sheets 101

What the heck is a sprite sheet?
Probably obvious to lots of people but to me (who last wrote a computer game 20+ years ago) unfortunately not. I'll keep this short and to the point.

Sprite sheets are used for animation of an object - and can be used easily by the HTML 5 Canvas element.

Consider the following four frames of animation for my Pacman-style game:





Now you might simply load these 4 png images as separate files - indeed there is no harm in doing so. However it is more efficient instead to create a Sprite-sheet - joining all the files together:


Now we only need to load one image not four - that is all a sprite-sheet is - a collection of images joined together at known offsets to allow easy extraction of each sub-image.


How to create a sprite sheet?
Since I use Linux for my desk top this was easy; I created the 4 individual images shown above and called them:

pac_right1.png
pac_right2.png
pac_right3.png
pac_right4.png

Then the "montage" command from the "ImageMagick" collection of programs was used to join them together:

montage -background "transparent" -geometry 24x24 -tile 4x1 \
  pac_right[1234].png pac_right.png

The result was a file called "pac_right.png" which contained all 4 images at the original resolution of 24x24 as shown in the second example.

How to use a sprite sheet on a Canvas?
This is a matter of loading an image initially, for example (overly simplistic):

var im=new Image();
im.src='images/pac_right.png';

This is overly simplistic because it does not take into account that images are loaded asynchronously - the image might not be available for a short while above the above code has been run - more on that next time!

Once the image is available it is a matter of using the "drawImage" method made available by the canvas element. This takes the following arguments:

canvas.drawImage(
    image,            // The image to draw (our sprite sheet)
    x_offset,         // The X offset in image of partial image to draw
    y_offset,         // The Y offset in  image of partial image to draw
    width,            // Width in pixels of part of image to draw
    height,           // Height in pixels of part of image to draw
    canvas_x_offset,  // Offset in pixels from left of canvas
    canvas_y_offset,  // Offset in pixels from top of canvas
    target_width,     // Width of image to draw on canvas
    target_height     // Height of image to draw on canvas
);         

Given that the sprite sheet in the example of a tile of 4 images across then the "y_offset" I will use will always be 0. The "x_offset values will be 0,24,48,72 for the for partial images.

So the first five parameters determine the image and the portion of it you wish to display on the canvas. The next two - canvas_x_offset and canvas_y_offset determine where on the canvas to put the image. The final two indicate the size of the image to display. Some points of interest:


  • The offset values on the canvas are typically real numbers, but including fractions may slow down rendering the image size the canvas implementation might attempt to dither the image in an attempt to mimic the fractional positioning - so typically make sure whole values are passed.

  • If the target_width and target_height parameters are different than the width and height parameters then the image will be scaled to this new size.
Putting it together
The following takes the concepts above and creates a canvas, loads a sprite sheet and displays the 4 sub-images on the canvas with scaling:



<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var pac_left;
pac_left=new Image();
pac_left.onload=function() { draw_it(); };
pac_left.src='pac_left.png';


function draw_it() {
var canvas = document.getElementById('sprites');
console.log("canvas=",canvas);
var ctx=canvas.getContext('2d');
ctx.drawImage(pac_left,0,0,24,24,0,0,24,24);
ctx.drawImage(pac_left,24,0,24,24,50,0,32,32);
ctx.drawImage(pac_left,48,0,24,24,100,0,40,40);
ctx.drawImage(pac_left,72,0,24,24,200,0,48,48);
}
</script>
</head>
<body>
<h1>testing ...</h1>
<div id="maze" style="position:relative; width:720; height:480">
<canvas id="sprites" style="z-index: 1; position:absolute; left:0px; top:0px" width="720"  height="480"></canvas>
</div>
</body></html>


HTML Canvas Demo 1







2 comments:


  1. Thank you for this blog
    Love is a powerful emotion, and it can be healing. While love can’t fix everything or prevent someone from developing a mental illness, it does support good overall physical and mental health.
    Signs he likes you
    best friend breakup

    ReplyDelete