Spritesheets
A spritesheet is a set of images stitched together into a single image file, normally laid out as a grid of rows and columns. Spritesheets allow a game engine to download and load a single image file instead of many small image files, which can be a more efficient use of memory and bandwidth.
Common usages of spritesheets include:
- Storing all the animation frames of a character in a single image file.
- Storing all the tiles of a tileset in a single image file. For example, there might be one spritesheet for the volcano tileset, filled with igneous rocks, lava and ash, while another winter tileset spritesheet might contain snow, ice and pine trees.
Many authoring tools produce spritesheets, including Aseprite, TexturePacker, and Shoebox.
Minimal Example
// Declare the tilset
pub import WinterTileset from Spritesheet(@winter.png, tileSize=16, count=132, gap=1)
pub game fn World.Main() {
Spawn tree {
use body=tree
Body(pos=@(0,0), immovable=true)
// Use the image at index 77 of the WinterTileset spritesheet
ImageSprite(image=WinterTileset[77], radius=5)
}
}
Declaring Spritesheets
Use the import keyword to declare a spritesheet in Easel, like this:
pub import DungeonTileset from Spritesheet(@dungeon.png, tileSize=16, count=132, gap=1)
Image file:
- The first parameter is always the image file, e.g.
@dungeon.pngor@hero.svg. Easel will search your project to find the file that matches the name you provide. See Assets to learn more about how Easel finds assets.
Tile size:
It is required to specify the tileSize.
tileSize(Number): The size of each subimage in the spritesheet, in pixels. For example, if your spritesheet is made up of 16x16 pixel tiles, you would settileSize=16. Provide a Vector if your tiles are not square, e.g.tileSize=@(16,32)for 16x32 pixel tiles.
Tile grid:
Both of these parameters are optional.
margin(Vector or Number): The position of the top-left corner of the first tile in the spritesheet, in pixels. Defaults to@(0,0).gap(Number): The number of pixels between each tile in the spritesheet. Defaults to0.
Tile selection:
It is required to specify the number of tiles to import, either by providing the count parameter,
or by providing both the numCols and numRows parameters.
count(Number): The total number of tiles to import. If bothcountandnumCols * numRowsare provided, the smaller of the two will be used.numCols(Number): The maximum number of columns to import. This parameter can be used to import only a subset of columns in the spritesheet.numRows(Number): The maximum number of rows to import. This parameter can be used to import only a subset of rows in the spritesheet.skip(Number): The number of tiles to skip at the beginning of the spritesheet. Defaults to0. Use this to import a subset of the tiles, for example if you only want the walking animation frames of a character and not the idle frames.
Easel is a multiplayer game engine. The number of tiles must be specified so that the Spritesheet can be statically allocated at compile time to be the same length for all players. This ensures all players have a synchronized view of the game world, even if some players are still haven't yet downloaded the spritesheet due to a slow or unstable internet connection.
Tile Order
Tiles will be imported in row-major order,
starting from the top-left corner of the spritesheet and moving left-to-right across each row, then down to the next row.
The first tile in the spritesheet will be at index 0, the second tile at index 1, and so on.
Using Spritesheets
A spritesheet gets allocated as a static Array of Assets, so you can access each tile by its index in the array:
let treeImage = WinterTileset[77] // Get the image at index 77 of the WinterTileset spritesheet
Certain functions like ImageSprite can take an array of images as input, and they will automatically animate through the images in the array. For these functions, you can just pass in the entire spritesheet array to them:
// Declare the tilset
pub import HeroWalkingImages from Spritesheet(@hero-walking.png, tileSize=16, count=25, gap=1)
pub fn unit.Hero([owner]) {
use body=hero, radius=0.5
Body(pos=@(0,0))
// Animate through all the images in the HeroWalkingImages spritesheet at 10 frames per second
ImageSprite(image=HeroWalkingImages, frameInterval=0.1s)
}
Spritesheets are also a great data source for Tilemaps, refer to the Tilemaps section to learn more.