Skip to content

Spritesheet based animation

Igor Zinken edited this page Dec 30, 2023 · 11 revisions

Sprite sheets

A Sprite instance always references a single resource. However it is not unlikely that you want to have different visual states for your Sprite if you're for instance creating a game, perhaps you will even be showing animations, for this purpose a sprite sheet is your friend!

Sprite sheets for dummies

A sprite sheet is basically a single image (usually with transparency, so PNG is also your friend here!) that consists of multiple tiles, each of equal size. Each tile contains basically a different frame of an animation. If you for instance have an animation of a walking character, each unique frame will appear as a tile in your sprite sheet.

Creating a sprite sheet

Creating a sprite sheet is simple, you first select on a tile size. This means that all the frames of your animation must fit within that tile size. Let's say we select 40 by 60 pixels. If you have a single animation of 10 frames, you will be creating an image of (40 pixels * 10 frames ==) 400 by 60 pixels. Every 40 pixels the next frame of the animation is placed.

Combining multiple animations within a single sprite sheet

...is encouraged! On the one hand it is nice that your application will have to download less files, but also from a maintainability point of view it is convenient to have all animations of a specific object/character be in a single file.

The only thing to keep in mind is the maximum image file size most browsers accept and that zCanvas animations must all be on a single column.

Columns ?

A sprite sheet does not have to be a single strip of tiles, but can be a matrix. For example consider this sheet of the Prince of Persia 2 character:

Prince of Persia 2 character sheet

You may see several different animations, for instance:

  • Turning around from facing left to right (first row, first 9 images)
  • Turning around from running left to right (first row, 9 images starting from tile index #9)
  • Jumping up from standstill (second row, first 16 images)
  • etc.

You can cluster several animations (a.k.a. different states for your character/object) in this matrix. Just remember that in zCanvas a unique animation/state cannot exceed a single row.

Using a sprite sheet with a Sprite

A sprite sheet is passed to a Sprite as any other image, namely by providing a resourceId to the constructors initializer Object, or by calling setResource() directly. The same can be done for a sprite sheet, where on one part you provide the bitmap, and on the other you provide the sheet. You can do this by either providing a sheet to the constructors initializer Object or by calling setSheet() directly (just keep in mind that the width and height of your sprites bounding box are a single tile in the sheet size, NOT the full image size). The sheet is provided as an Array that contains Objects describing each animation/state. These Objects are of the following type:

type SpriteSheet {
    row: number;
    col: number;
    amount: number;
    fpt: number;
    onComplete: ( sprite: Sprite ) => void;
}

where all properties are required with the exception of onComplete being optional. The properties describe:

  • row: the row index (starting at 0) for the animation
  • col: the column index (starting at 0) for the animation
  • amount: the amount of frames the animation lasts
  • fpt: frames per tile, in other words: how many frames the canvas will display a single tile in the animation
  • onComplete: an optional handler that is fired when the animation ends.

Animations will loop indefinitely unless you specifically change the animation (see zCanvas.sprite.switchAnimation()). This can be desired, but maybe you want to be notified when an animation ends (for instance: because the animation is an explosion that at the end should clean up the sprite). For this purpose you can define an onComplete handler that is fired as soon as the last frame of the animation has played for its full duration.

You can calculate an appropriate value for fpt by using the frame rate of the zCanvas.canvas. If the framerate is for instance 60 fps, there will be 60 frames in a single second. If you have an animation that consists of 15 tiles/frames that you wish to display over a full second, the frames per tile are: (60 fps / 15 tiles ==) 4 frames per tile.

Example sheet list

This is an example list for the Prince of Persia sprite displayed above.

const list = [
    { row: 0, col: 0, amount: 9,  fpt: 4 }, // turnaround from standstill
    { row: 0, col: 9, amount: 9,  fpt: 4 }, // turnaround while running
    { row: 1, col: 0, amount: 8,  fpt: 4 }, // running to standstill
    { row: 1, col: 8, amount: 13, fpt: 4 }, // running animation
    { row: 2, col: 0, amount: 16, fpt: 4, onComplete: onHanging }, // grab ledge 
    // etc. etc...
];

The Sprite will automatically assign the first animation (index 0 in the list Array) as the starting animation and loop it indefinitely. If you want to change your animation to reflect a different state for your Sprite, you simply invoke:

switchAnimation( tileIndex: number ): void

on your Sprite-instance and provide numerical value tileIndex to indicate which animation inside your sheet list should play next.

Clone this wiki locally