-
Notifications
You must be signed in to change notification settings - Fork 69
Sprites
32blit supports 128x128 pixel sprite sheets containing 64 8x8 sprites. The engine is optimised to work with these particular sizes but larger assets can be represented using multiple individual sprites.
Since 32blit has no hardware sprite engine there is no hard limit to the number of sprites that can be displayed at the same time. However excessive sprite use will affect the framerate.
Sprites are typically expected to be loaded via the asset pipeline using the 32blit tool to convert a 128x128 pixel PNG image with 255 or fewer colours into a packed, palette-based asset.
Given the file assets/sprites.png
the following assets.yaml
will convert it into an assets.cpp
and assets.hpp
file containing a uint8_t
array asset_sprites
that contains the packed data:
assets.cpp:
assets/sprites.png:
name: asset_sprites
The CMakeLists.txt
file must then register assets.yml
as part of the build:
blit_assets_yaml(application-name assets.yml)
And the resulting asset.hpp
should be included into the application:
#include "assets.hpp"
This data can be unpacked into the screen spritesheet ready for use:
void init() {
screen.sprites = SpriteSheet::load(asset_sprites);
}
screen.sprites
is expected to be a SpriteSheet
which derives from Surface
and adds some helper functions for loading packed data and determining sprite bounds.
A SpriteSheet
can be declared as:
SpriteSheet *more_sprites;
And then loaded at runtime with packaged data:
more_sprites = SpriteSheet::load(packed_data);
Since more_sprites
is effectively just a Surface
it can be copied to the screen
with blit
, which accepts a Rect()
describing the source region pixels and a Point()
describing the destination location in pixels.
For example, the following are equivalent:
screen.blit(more_sprites, Rect(0, 0, 8, 8), Point(0, 0));
screen.sprites = more_sprites;
screen.sprite(0, Point(0, 0))
However, blit
offers more flexibility† and can operate on regions of the SpriteSheet
that are not aligned to the 8x8 grid.
- † at the expense of performance?
A 128x128 spritesheet contains 64 individual 8x8 sprite tiles numbered 0 to 63 following across left to right.
The top left tile is thus tile 0 and the top right is tile 7. Immediately below on the next row the left and right tiles are 8 and 15 respectively, and so on.
A single sprite can be drawn to the drawn via its index at a given Point()
:
screen.sprite(1, Point(30, 30));
Sprites can be addressed by their column and row location, ranging from 0 to 15 in both cases.
A sprite with index 1 is also addressable as row 0, column 1. A Point()
is used to specify this location, in this case it would be Point(0, 1)
.
A single sprite can be drawn via its location at a given Point()
:
screen.sprite(Point(0, 1), Point(30, 30));
When addressing sprites by their row/column location a Rect()
can be supplied in lieu of a Point()
, giving both the row and column of the first sprite, and a width/height value to specify how many sprites wide and high the draw should include.
The first four sprites in the top row of the spritesheet can be drawn like so:
screen.sprite(Rect(0, 0, 4, 0), Point(0, 0));
The four top left most sprites in a grid of 2x2 can be drawn like so:
screen.sprite(Rect(0, 0, 2, 2), Point(0, 0));
Large groups of sprites, such as those used to construct a level, are easier to manage using a TileMap
- effectively a 2d array of tile IDs and additional attribute flags. For more information on drawing with TileMap
s see: TODO: TileMap page and link here