The LAND auction has started, participate and buy LAND before it ends! Learn More
Hello! Please choose your
desired language:
Dismiss

Sprites have been used in game development for decades. The first game to use sprites was Basketball, and it came out in 1974!

What are sprites?

Sprites are simply two-dimensional bitmap graphics. They can be static images or animations integrated directly within a larger scene. Back in the era of 2D games, they were used to construct entire realities – Galaxian (shown below) used RGB sprites for the very first time in a video game.

44 years later, we’re still using them.

Using sprites in Decentraland scenes

In this tutorial, we’ll take a look at how to integrate sprites into your Decentraland scenes. Sprites, present in virtually every contemporary video game, allow you to add bitmap imagery to your scenes. You can use sprites to make menus, billboards, animated materials, and more.

To add a sprite to your scene, you’ll either need a “sprite sheet” or an “image atlas”. A “sprite sheet” is a collection of still images that are neatly arranged into rows and columns and progress to make up an animation. An “image atlas” is a large image file that contains a series of images that may be of varying sizes and that are arranged into whatever positions fit best. Below are a couple examples of a sprite sheet and image atlas:

Sprite Sheet

Image Atlas

For the rest of this tutorial, we’ll use this image atlas:

and this sprite sheet:

Feel free to use your own or another one you’ve found, but make sure to change the values in the code to reflect the new imagery.

Installing dependencies

In the Decentraland SDK, interacting with sprites is different from interacting with other elements. In order to use sprites, we’ll need to install a new dependency and learn how the SDK interacts with bitmap imagery.

To begin, let’s install the sprites helper into our scene.

Spin up npm in your terminal or command prompt and run the following in your scene folder:

npm i --save dcl-sprites

After installing the dependency, import it into your scene’s .tsx file:

import { createSpriteSheet, createAtlas } from 'dcl-sprites'

With our dependencies installed, we’re ready to go!

Building a UI with sprites

Let’s start off by building a simple UI for our scene.

We’ll need our image atlas, and some simple code to interact with it.

We need to call a function that defines how each of the different images in the atlas are mapped, giving each image a label.

Call the createAtlas() function and define a custom class:

const UIPlane = createAtlas({
  material: "#material",
  textureSize: { width: 1000, height: 550 },
  frames: {
    play: { x: 26, y: 128, width: 128, height: 128},
    start: { x: 183, y: 128, width: 128, height: 128 },
    exit: { x: 346, y: 128, width: 128, height: 128 },
    expand:{ x: 496, y: 128, width: 128, height: 128 }
  }
});

When using the createAtlas() function, the SDK is looking for three parameters:

  • material: A reference to a material or basic-material entity. This material will use the texture atlas image file as the texture.
  • textureSize: The dimensions (in pixels) of the image file.
  • frames: A comma-separated list of all the images to extract from the atlas. For each image, you need to have a name, x and y coordinates, and width and height parameters.

With the code above, you can see how each image is defined using x and y coordinates, as well as a width and height parameter.

Before we move on, we need to add a custom material in our scene to define our sprite sheet.

<basic-material
  id="material"
  texture="materials/image-atlas-ui.png"
/>

Remember that materials are referenced using a hashtag. So if the id of your material is “material”, you reference it by typing #material.

With our frames defined and our material ready to go, all we have to do is add some UIPlane calls to our scene, and we’re done!

Here’s the code in all of its entirety:

import { createAtlas } from 'dcl-sprites'
// ...
async render() {
  const UIPlane = createAtlas({
    material: "#material",
    textureSize: { width: 1000, height: 550 },
     frames: {
      play: { x: 26, y: 128, width: 128, height: 128 },
      start: { x: 183, y: 128, width: 128, height: 128 },
      exit: { x: 346, y: 128, width: 128, height: 128 },
      expand:{ x: 496, y: 128, width: 128, height: 128 }
    }
  });

  return (
    <scene>
      <basic-material
        id="material"
        texture="materials/image-atlas-ui.png"
      />
      <entity position={{ x: 5, y: 1, z: 5 }}>
        <UIPlane
          frame="play"
          position={{ x: 0, y: 1, z: 1 }}
        />
        <UIPlane
          frame="start"
          position={{ x: 0, y: 1, z: 2 }}
        />
        <UIPlane
          frame="exit"
          position={{ x: 0, y: 1, z: 3 }}
        />
      </entity>
    </scene>
  );
}

Creating animations using sprites sheets

Now, let’s take a look at how you can use sprite sheets. Once again, a sprite sheet is a series of images, all arranged into rows and columns in one image file, meant to be spliced together into an animation. The dcl-sprites library automates the UV mapping of the frames, based on your specifications.

For this example, we’ll use our explosion sprite sheet:

Start off by calling a createSpriteSheet function to define a custom class that uses the texture from the sprite sheet:

const Sprite = createSpriteSheet({
  material: "#explosion",
  textureSize: { width: 512, height: 512 },
  cellSize: { width: 171, height: 171 }
})

With the createSpriteSheet() function, three arguments are taken once again.

  • material references a material or basic-material entity where the sprite sheet is used as its texture.
  • texturesize defines the dimensions (in pixels) of the sprite sheet image file.
  • cellSize defines the dimensions (in pixels) of each frame. All frames are assumed to be uniform with no padding and margins.

Once again, we need to first define a material entity in our scene to reference on this function. Add this

<basic-material
  id="explosion"
  texture="materials/sprite-sheet-explosion.png"
/>

Once we’ve defined our custom function, we can add a new entity with the class Sprite to our scene:

<Sprite
  frame="frame0"
  position={{ x: 2, y: 2, z: 3 }}
  scale={{ x: 1, y: 1, z: 1 }}
/>

The entity we create must have a frame property to specify which frame to display. Frame numbers will be automatically generated by the createSpriteSheet() function - starting at 0 and going to n.

Let’s take a look at the whole picture of our render function:

// import { createSpriteSheet } from 'dcl-sprites'
// ...
async render() {
  const Sprite = createSpriteSheet({
    material: "#explosion",
    textureSize: { width: 512, height: 512 },
    cellSize: { width: 171, height: 171 }
  })
  return (
    <scene>
      <basic-material
        id="explosion"
        texture="materials/explosion_atlas_512x512.png"
      />
      <entity position={{ x: 5, y: 1, z: 5 }}>
        <Sprite
          frame="frame0"
          position={{ x: 0, y: 1, z:1 }}
        />
      </entity>
    </scene>
  );
}

The previous example shows a single frame from your sprite sheet and doesn’t animate it. If you want to have the sprite actually cycle through its frames, you need to change the value of the frame field at a regular interval. You do this by using a reference to a variable in the scene state instead of a literal value.

frame={"frame" + this.state.frame}

The code below animates the sprite. It uses a setInterval() to change the value at a regular interval.

import * as DCL from 'decentraland-api'
import { createSpriteSheet, createAtlas } from 'dcl-sprites'

export default class SampleScene extends DCL.ScriptableScene {
  state= {
    frame: 0
  }

 sceneDidMount(){
    setInterval(() => {
      let frameNum = (this.state.frame += 1) % 8
      this.setState({ frame: frameNum })
    }, 200)
 }

async render() {
    const Sprite = createSpriteSheet({
      material: "#explosion",
      textureSize: { width: 512, height: 512 },
      cellSize: { width: 171, height: 171 }
    })
    return (
      <scene>
          <basic-material
            id="explosion"
            texture="materials/explosion_atlas_512x512.png"
          />
         <entity position={{ x: 5, y: 1, z: 5 }}>
          <Sprite
            frame={"frame" + this.state.frame}
            position={{ x: 0, y: 1, z:1 }}
          />
        </entity>
      </scene>
    );
}

Helpful tools

Sprites are a powerful tool to use in your scenes. Below are a couple of useful tools that you can use to help build and visualize your sprites before you bring them into Decentraland.

Our developers are working hard to build the tools you need to create anything in the Multiverse. If you have any questions, make sure to refer to our Docs, or reach out to us in the #support-sdk Discord channel.

We’re also working to make our docs the universal source of truth for everything related to the SDK. Please open a pull request or an issue on GitHub if we’re missing something that you need.

Start Building!
Our SDK provides everything you need to start developing games and applications.
Get Started