Solar2D fully supports image sheets, sometimes referred to as sprite sheets or texture atlases. This allows you to load multiple images/frames from a single larger image file. Image sheets can be used for both static images and animated sprites.
In mobile app design, where devices have limited texture memory, it’s often essential to conserve this memory by using image sheets. In most cases, it is more efficient to consolidate several smaller images onto one larger sheet and “pull” a particular image from the sheet when you want to display it on the screen. Solar2D offers this functionality via image sheets.
Image sheets are also a convenience feature. Using popular
For a more detailed explanation of the memory benefits of image sheets, please refer to the Performance and Optimization guide.
The syntax for a new image sheet requires, at minimum, the name of the file and a table of options which tells Solar2D about the images contained on the overall sheet. Depending on your needs, these options can be in “simple” format or “complex” format. If you’re using a texture packing utility like those mentioned above, this task will typically be handled for you.
Initializing the image sheet is done with the graphics.newImageSheet() function:
graphics.newImageSheet( filename, [baseDir, ] options )
filename
— this is the name of the image file that includes all frames of the image sheet.
baseDir
— specifies the base directory (system directory constant) where filename
is located.
options
— a table with keys and/or sub-tables that represent specific options related to the image sheet.
This configuration assumes that all frames in the image sheet share identical size properties (width and height).
local options = { width = 50, height = 50, numFrames = 3 } local sheet = graphics.newImageSheet( "mySheet.png", options )
This configuration is required if the image sheet has frames of varying sizes. In this configuration, options
consists of an array of tables within a parent frames
table. Each table in the array represents a single frame in the image sheet. For each frame, you must specify the x
and y
start width
and height
of the frame. Taken together, these four parameters encompass the rectangular bounds of the frame.
For example, consider the following image sheet (mySheet.png
) with two frames of varying width:
232 | 277 | |
276 |
The image sheet setup would look like this:
local options = { frames = { { -- frame 1 x = 0, y = 0, width = 232, height = 276 }, { -- frame 2 x = 232, y = 0, width = 277, height = 276 } } } local sheet = graphics.newImageSheet( "mySheet.png", options )
Just like individual images displayed with display.newImageRect(), image sheets may be selected dynamically depending on the screen resolution. To accomplish this, you must specify the following key-value pairs in the options
table:
sheetContentWidth
sheetContentHeight
These values tell Solar2D the size of the original 1x image sheet. For example, if you’re developing for both iPad and iPad Retina, and you’re using an image sheet of 1000×1000 for the regular iPad, you should specify 1000
for both of these values and then design your Retina image sheet at 2000×2000.
local options = { width = 100, height = 100, numFrames = 10, sheetContentWidth = 1000, --width of original 1x size of entire sheet sheetContentHeight = 1000 --height of original 1x size of entire sheet } local sheet = graphics.newImageSheet( "mySheet.png", options )
For details on content scaling and dynamic image selection (which applies to image sheets too), please refer to the Project Configuration guide.
To display an image (frame) from an image sheet, use the existing display APIs but specify the sheet and a frame number instead of just the image name:
local sheet = graphics.newImageSheet( "mySheet.png", options ) local frame1 = display.newImage( sheet, 1 ) local frame2 = display.newImage( sheet, 2 )
If you require dynamically-selected images, use display.newImageRect() and specify the width and height as usual:
local sheet = graphics.newImageSheet( "mySheet.png", options ) local frame1 = display.newImageRect( sheet, 1, 232, 276 ) local frame2 = display.newImageRect( sheet, 2, 277, 276 )
As noted above, popular image packing programs offer the option to maximize (compact) your image sheets. Essentially, this means that the source images will be trimmed of empty surrounding space before they’re packed into the final image sheet. These programs make intelligent use of the overall sheet dimensions and automatically arrange the images into the most efficient layout possible. For example, if you want to pack the two individual bird images into one image sheet using a packing program, the result may be as follows:
+ | = |
Note that the transparent space, represented by the gray checkerboard in the above examples, is trimmed off and the birds are packed closely together to achieve the smallest possible image sheet. With this change, the image sheet is now 450×262 instead of 512×276.
While trimming is often necessary to achieve the smallest possible image sheets, there are some important usage notes that you must be aware of, particularly in regards to positioning.
When you place one of these images on the screen or use them in a sprite animation, you will typically want the images to be positioned as if they were not trimmed — meaning, the empty space that was trimmed is respected, not discarded, in regards to screen positioning. This ensures that the images align properly with each other, especially in an animation where the trimmed area will often vary per frame.
Solar2D manages this with some additional parameters in the image sheet setup. These include sourceX
, sourceY
, sourceWidth
, and sourceHeight
. These are added to the image sheet options
as follows:
local options = { frames = { { -- frame 1 x = 0, y = 0, width = 203, height = 256, sourceX = 60, sourceY = 11, sourceWidth = 277, sourceHeight = 276 }, { -- frame 2 x = 203, y = 0, width = 247, height = 262, sourceX = 16, sourceY = 5, sourceWidth = 277, sourceHeight = 276 }, }, sheetContentWidth = 450, sheetContentHeight = 262 } local sheet = graphics.newImageSheet( "mySheet.png", options )
Notice how in both frames, the sourceWidth
and sourceHeight
parameters match the size of the original, untrimmed frames. This imaginary “canvas” is what you must consider when positioning a trimmed image on the screen. Effectively, the image will be positioned in respect to the center point of the untrimmed frame size.