loading...
Cover image for JS Animation

JS Animation

leamsii profile image Liam Escribano ・2 min read

Hello and good morning! Today I will be showing you how to turn a sprite sheet into an animation sequence using JavaScript. Here is the sprite sheet we will be working with and the final result.

Dog Sprite Sheet
Dog Walking

Prerequisites

  • An understanding of the HTML canvas and context
  • Basic knowledge of JavaScript classes
  • A bit of async and await

Things to note about this sprite sheet

  • Has a total of 8 frames
  • Each frame is exactly 113x79 pixels

Our First Class

class Sprite {
  constructor(src, width, height, frames) {
    this.image = new Image;
    this.image.src = src;
    this.width = width;
    this.height = height;
    this.frames = frames;
  }
}

This class is in charge of maintaining the properties of a sprite sheet. The width and height properties belong to the expected width/height for all of the frames in the sheet (113x79).

The Animation Handler

class AnimationHandler {
  constructor(sprites) {
    this.sprites = sprites;
    this.currentSprite = sprites[0];
    this.loop = true;
    this.currentSprite.image.onload = this.render();
  }
...

The AnimationHandler class takes in an array of Sprite Objects and calls the render function in a looping state after the sprite loads.

The Brains

...
async render() {
    for (let i = 0; i < this.currentSprite.frames; i++) {
      context.clearRect(0, 0, canvas.width, canvas.height);
      context.drawImage(this.currentSprite.image, (this.currentSprite.width * i), 0, this.currentSprite.width, 
      this.currentSprite.height, 50, 50, this.currentSprite.width, this.currentSprite.height);

      await sleep(80)
    }
    if (this.loop) {this.render();}
  }

We first define an asynchronous function named render using the async keyword. This allows us to run multiple animations at once without creating blockage.

We then create a basic for loop to loop over the number of frames. For every frame we do these things in order.

  1. Clear everything on the canvas
  2. Draw the sprite image and crop it to show the current frame
  3. Pause the loop for 80 milliseconds before continuing
  4. Use recursion to keep the animation running

Check this link out to learn about how context.drawImage works MDN

You may be asking yourself, "Where the hell is the sleep function defined?!" I decided to keep it out of this tutorial to avoid confusion. The sleep function just returns a Promise after setTimeout.

Putting It All Together

const dogIdle = new Sprite(dog_idle, 109, 79, 4);
const dogMoving = new Sprite(dog_moving, 113, 79, 8);
new AnimationHandler([dogMoving, dogIdle])

We create two Sprite instances and pass in the required parameters. Then we create an AnimationHandler instance for the sprites. This should automatically play the first sprite sheet you pass i although the class can be easily modified to jump between animations and even pause them.

Here is the idle we defined above and an attacking animation.

sheet
dog idle
attacking

Thank you for reading ! I left a few things out for the sake of keeping this simple. Like defining the canvas and context and the sleep function.

Posted on by:

leamsii profile

Liam Escribano

@leamsii

I'm a full stack web developer. I love Python and my last name literally means 'writer'.

Discussion

pic
Editor guide