DEV Community

Cover image for Simple Sprite Animations for Games on The Web - (Digital Ocean Hackathon Blog: Part 1)
Jeff Puls
Jeff Puls

Posted on

Simple Sprite Animations for Games on The Web - (Digital Ocean Hackathon Blog: Part 1)

One of the greatest advantages to building applications for the web is the low barrier to entry when it comes to easy, yet powerful graphics and animation.

It's no secret, HTML and CSS make up the backbone of everything you see and interact with on the Web. Once you add a splash of JavaScript, you can have your own fully-featured application, able to be used by anyone all over the world. What goes great with simple, powerful graphics and an intuitive programming language? Video games, naturally!

(a quick preface here, I don't want you to expect to crank out the next Call of Duty in your web browser after reading this series of tutorials, but something akin to a basic NES-style game? Sure, why not!)

If you don't care about the background and want to get to the meat-and-potatoes of this post, skip to this section.

Background: The Humble Sprite

What is a sprite anyways?

There are two basic categories when it comes to video game graphics: 2D and 3D. This post focuses on the prior, as it is the quickest and easiest to get going without needing any additional libraries, software, or prior graphics knowledge.

The most basic method of creating graphics and the illusion of motion for 2D games is by implementing a special set of images, known as sprites. At the core, a sprite is just an image which can be used to represent an entire object, or cleverly combined with other sprites as part of a larger whole. In the olden days of video game development, this was the go-to method for rendering graphics before 3D graphics tech had matured.

A sprite can be anything you want. Something as simple as a single-pixel square can represent the flying ball in Pong, or an elaborately illustrated character of your own design, the limits are only that of your own imagination.

How does sprite animation work?

We humans like to believe that we are super intelligent beings, that nothing can fool us. In reality, that couldn't be farther from the truth, especially when it comes to how we process visual information. If we view a series of similar images displayed in rapid succession, our brains have a hard time deciphering what is going on, and simply assumes it is the same object, just moving.

Sprite animation exploits this phenomenon at the most basic of levels. Typically, sprites for similar objects are all combined into one, larger image known as a sprite sheet, each individual sprite can be thought of as individual frames of a video. All the computer has to do to trick our meager caveman brains is to rapidly switch which part of the sprite sheet is displayed. Done right, we think we see our game's hero bravely marching into battle for instance, when in reality, its just the same two images being rapidly flipped back-and-forth.

For the purposes of this post, I am going to limit the examples to 8-frame, single-row sprite sheet examples, however you can in theory use as many frames as you'd like!

Example

Here is a very simple example of how the walking animation for Link from The Legend of Zelda on the NES works. Note how there are two distinct frames side-by-side in one image, this is the sprite sheet. (If you're coding along, you can save the sprite sheet PNG below to the same directory as your HTML and CSS files).

Link Sprite sheet

By rapidly switching between sprites, you get the basic walking animation!

Link walking gif

Getting set up

The HTML

This post assumes that you possess a basic working knowledge of HTML/CSS, although if not, the concepts here should be pretty easy to follow.

We will begin with the basic HTML5 boilerplate, with the inclusion of a <link> tag to our CSS and <script> tag to a JavaScript file that we will create in the next part of this series:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>Sprite Animation Demo</title>
</head>
<body>
     <script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode



The following elements will all be included within the <body> of the document, before the <script> tag.

<div class="sprite-view-frame">
    <div class="sprite-renderer"></div>
</div>
Enter fullscreen mode Exit fullscreen mode



Here, you can imagine the sprite-view-frame as a picture frame that crops the visible portion of the image (a single sprite). The sprite-renderer will be the element that holds the entire full-size sprite sheet.

That's it for the HTML... no, really!

The CSS

Animating sprites in this manner only requires some very basic CSS properties to be set, I will explain what is necessary and why below. Begin by creating a styles.css file in the same directory as your HTML file. The sprite sheet we will be using in this example contains two 32px by 32px sprites, giving us total dimensions of 64px by 32px.

First, lets set some basic properties to make the body a bit nicer to look at.

body {
  background-color: #222222;
  height: 100vh;
  margin: 0;
  position: relative; /* this allows us to center the sprite-view-frame on the page */
}
Enter fullscreen mode Exit fullscreen mode

Now, we can set some CSS variables to keep our code DRY later in the project. Simply adjust these values based on the sprite sheet in use:

:root {
  --sprite-width: 32px;
  --sprite-height: 32px;
  --sprites: 2;
  --animation-length: .5s;
}
Enter fullscreen mode Exit fullscreen mode

Next, we will style the sprite-view-frame element. Note that the position, top, left, and transform properties will become more important later when we make our sprites interactive.

.sprite-view-frame {
  width: var(--sprite-width);
  height: var(--sprite-height);
  overflow: hidden; /* this will hide any sprites outside of the frame*/

  /* position the view frame on the page */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate3d(-50%, -50%, 0);
  /* ********************************** */
}
Enter fullscreen mode Exit fullscreen mode

After we have a frame to display the sprites, we can style the sprite-renderer element itself, which will be used to display and animate the sprite sheet.

.sprite-renderer {
  width: var(--sprite-width);
  height: var(--sprite-height);
  background-image: url("./link-spritesheet-1.png"); /* the sprite sheet */
  background-repeat: no-repeat;

  /* this prevents the browser from aliasing our pixel art image and making it blurry */
  -ms-interpolation-mode: nearest-neighbor; 
  image-rendering: -webkit-optimize-contrast;
  image-rendering: -moz-crisp-edges;
  image-rendering: -o-pixelated;
  image-rendering: pixelated;

  /* this is where the magic happens! */
   animation: animateSprites var(--animation-length) infinite steps(var(--sprites));
}
Enter fullscreen mode Exit fullscreen mode

Finally, the most important part: the animation itself!

@keyframes animateSprites {
  0% {
    background-position: 0px;
  }
  100% {
     background-position: calc(var(--sprite-width) * var(--sprites) * -1);
  }
}
Enter fullscreen mode Exit fullscreen mode

Basically, all our CSS needs to do is rapidly shift the background image of the sprite-renderer to display each sprite. The initial state of the animation will bring the first sprite (on the left) into view. Then, it will shift the image to the left by the total width of the sprite sheet, thus displaying the last sprite (on the right).

Here is a breakdown of what the animation property within .sprite-renderer is doing:

  • animation
    • animateSprites | the name of the keyframes we defined
    • var(--animation-length) | the entire animation lasts .5 seconds, or .25 per frame
    • infinite | the animation will loop forever
    • steps(var(--sprites)) | This is the most important part! This tells CSS that for each sprite, render that stage of the animation as a distinct frame, rather than interpolating between start and end states.

That's it!

If you open your HTML file in the browser, you should now have an animated Link marching in place on your screen.

The process for creating more detailed, higher frame rate sprite animations is largely the same. The only differences you need to account for in the CSS are the variables --sprite-width, --sprite-height, --sprites and optionally --animation-length.

Below is an example of an 8-frame sprite sheet, again featuring our friend Link, this time from A Link to the Past on the SNES. This sprite sheet is a bit larger than our previous example, featuring eight 64px by 64px sprites, for total dimensions of 512px by 64px:

Link sprite sheet 2

We need only to tweak the CSS as follows:

:root {
  --sprite-width: 64px;
  --sprite-height: 64px;
  --sprites: 8;
  --animation-length: .8s
}

Enter fullscreen mode Exit fullscreen mode

And when animated, you get this!

Link walking gif 2

Conclusion

You now possess the knowledge needed to animate your very own sprites, using some very basic HTML and CSS!

In my following post, we will dive into the code behind making your characters interactive with JavaScript!

Stay tuned!

DISCLAIMER:
I did not create, nor do I own any of the pixel art depicted in this post, I simply edited it such that it meets the requirements for this project. Credit for the sprites used goes to RetroGameZone.

Top comments (0)