Image Sheets, Image Groups, and Sprites

Share on Facebook0Share on Google+2Tweet about this on TwitterShare on LinkedIn0

NOTE: This tutorial is outdated and has been replaced by the Image Sheets guide.

Share on Facebook0Share on Google+2Tweet about this on TwitterShare on LinkedIn0

This entry has 84 replies

  1. dingo says:

    thanks for the tutorial!

    so, if i use texturepacker, i can use the resulting .lua file (getSpriteSheetData()) as an image sheet, without changing it? and simple call the new sprite api?


  2. Naveen says:

    @dingo I don’t think there’s a way we can use the .lua files that we get from 3rd party tools. I hope I’m wrong on that… it would suck to do everything manually. I currently use Zwoptex to export the lua file and I’m good to go.

    Is there any way to make 3rd party tools play nice with the new API, so we don’t have to manually make our Image Sheets for every single sprite animation we have?

  3. don says:

    @Naveen Spriteloq is already compatible with the new sprite engine. I’m working on integrating the new API calls in Spriteloq, but if the new engine does not support trimming yet, it might be best to wait.

    @Jonathan Beebe one thing not mentioned in this article is that the image sheets as of build 759 need to have dimensions that are a power of 2 otherwise the sprites will have garbled graphics. Hopefully this will be fixed in future updates, but if not your examples need to change. The dimensions for your simple example uses an image sheet that’s 70 x 82.

  4. Cleverson says:

    Great additions!
    Eager to see them on a stable release πŸ™‚

  5. Mark says:


  6. Great tutorial!

    I have a question, let’s say I have multiple sprites that came from the same image sheet, can I insert them into an image group? Will that increases the performance? Or I should just use normal display group as it doesn’t make any difference for sprites?

  7. @Naveen It looks like you can specify “old style” and use the old data files at least until the 3rd party tools catch up.

    Now, is it “old-style” “Old-Style” “old style” “ye olde style”???

    We can trial and error it I guess, but it’d be nice to know…

  8. Also, does “backwards-compatible” mean frame trimming IS supported if the “old style” option is selected?

  9. Hi, sorry but I have a few more questions:

    How do you remove sprites? “display.remove(sprite)” doesn’t work and causes the simulator to crash.

    And how do you dispose imageSheet?

  10. don says:

    @Jonathan Beebe I need to update my comment. The power of 2 thing looks like the result of using the old sprite API with the new sprite engine.

  11. StefanHQ says:

    The 3rd party tools will probably soon be up to date with this πŸ™‚

    I really like this. If I understand Image Sheet / Image Groups is more or less that it takes a whole punch of quad strips (objects/sprites) uses render those using the same texture. And this speeds up a lot as there will be only ONE drawcall to OpenGL.

    Love also that now there will be a stable and finally standard to index into a texture. That can be used then with higher “framwork” as sprite on top.

    Will Image Sheet properties be accessible (writable) once the object is created?
    This would allow us to write our own “Sprite” handler if we would choose to do so πŸ™‚

    Then we can make nice animations, squash, stretch even “inside” every object.


    Would also be wonderful, if that is possible to add “rotation” of that, just as in object. (imagine having “TV” screens, posters, billboards that animate, scroll messages in games)

    local options =
    frames =
    — FRAME 1:
    — all params below are required for each frame
    x = 2,
    y = 70,
    width = 50,
    height = 50,
    rotation = 30

  12. Jonathan Beebe says:

    Thanks for your comments and questions everyone! I have modified the article to include answers to many of the questions you asked, but here’s a quick summary:

    Using old spritesheet data: Yes, you can use the .lua files that are generated by third-party software, even if it exports to the old data format. See the updated ‘Sprite’ section in the article.

    Power of 2: Yes, your image sheet file dimensions must be a power of 2. See the updated ‘Image Sheets’ section, under the Power of 2 sub-heading in the article.

    Removing sprites: You remove sprites in the same manner as other display objects, and we are currently investigating the reported crashing issue.

    Old-style naming: You do not need to specify the type of options table you will be using, so you’ll never be typing “simple”, “complex” or “old-style” anywhere. You simply specify the required parameters for whichever one you’ll be using and the API is smart enough to know which one you are using.

    Sprites + Image Groups: Yes, you can insert sprites into an image group as long as the sequences use the same image sheet, and also the same image sheet as the specified image group. See the updated ‘Sprites’ section in the article for more info.

    I also updated the list of image group child object limitations as well, so please have another look at that in the ‘Image Groups’ section of the article.

    Thanks for your feedback and great questions so far everyone!

  13. Naveen says:


    So by using the old style, would it still be possible to get dynamic image resolution working so we can have @2x files? I don’t think so since the “sprite sheet data” would be different for each resolution… There wouldn’t just be 1 sprite sheet data for all resolutions.

  14. Jonathan Beebe says:

    For dynamic image resolution support, you’ll want to use the new options data format when creating your imageSheet.

    It would be best to switch over sooner than later, because since the old-style is deprecated, the only one we’ll support moving forward is the new simple/complex definitions.

    It’s also possible to write a function that converts your old data into the new ‘complex’-case format to make switching over a little easier. You could also write the function so that it adds in the required keys for dynamic image resolution once it ports over all your data.

    Cropped/trimmed sprite information won’t work at the moment, however, so you’ll need to wait until that gets pushed in if your app relies heavily on that.

  15. Fully Croisened says:

    This is definitely awesome!

    Jonathan, do you think there will be a time when the Image Groups will clean out their own children in the same way the normal display objects do? it would be nice if they both worked the same way on removal if possible, but I’ll happily clean up the image group children in the mean time. πŸ™‚

    Thanks so much for this, can’t wait to test drive it tonight!

  16. Simon says:

    Hi Jonathan, a few days ago I was wondering if offscreen objects are updated especially in a group. I have a VERY tall group in a scrollview and was wondering if my offscreen (large) display objects would be “updated” at all when I scroll.

    Do the new optimizations mean that only display objects which are visible (even if only 1 pixel is visible) will be processed?

  17. Martin Edmaier says:

    @Jonathan you should clearly say that you want to remove sprite sheets. Man is update will cost me a lot of money and rewriting my code and rescaling me images.

  18. Maciej says:

    I have two problems with new build.

    1. object:removeSelf() and display.remove(sprite) make simulator or app crash.

    2. When using sprites with time = 300 when changing sprite animation ( hero:setSequence(“heroright”) hero:play() ) it seems like the old one has to finish before the new one is loaded. Before it was changing right away. I can make more frames and less time to make it work again, but maybe there is no need because its gonna be changed ?

    Have an awesome day!

  19. Sanne says:

    How do you change the animation speed while an sprite is playing? IE in the movie clip API I would use spriteObject:setSpeed(0.5); …Is there a way to change the speed of the animation that I have set in the sequenceData? (i.e. time = 500 to time = 250?)

  20. Antheor says:

    Wonderful news ! Former API was too obscur for me πŸ™‚

    One question : in your complex example you write
    frames ={x=2,y=70,...}
    If tool line texturepacker does the sheet for you, it can be difficult to get those cood, right ?

  21. Nate Johnson says:

    @Jonathan Beebe
    You alluded to Apple’s iPad 3 (HD) announcement happening today. Does this mean that Corona is working on @4x or @HD file extensions so that we can have a 3rd image sheet recognized for the new iPad? Or is there another way to do this that I am just missing?

  22. Mark says:

    @ Sanne: spriteInstance.timeScale
    API lijst… luiaard πŸ˜›

    On a general note, good stuff! Time for some sprite heavy games πŸ˜‰

  23. Damir says:

    Can Image Groups be inserted into Display Groups ?

  24. David says:

    Similar question as Sanne: What if we have a “jumping” animation that we want to make look more realistic. So, 5 frames, but we don’t want an even 50ms between frames, we want something like this instead:

    Frame 1-2: 50ms
    Frame 2-3: 70ms
    Frame 3-4: 100ms
    Frame 4-5: 70ms

    I didn’t notice that documented, but can it be done?

  25. Jonathan Beebe says:

    @Nate: The new iPad’s resolution will be exactly double the dimensions of the previous iPad, similarly to how the iPhone4 was exactly double the resolution of the 3GS. As long as you provide @2x versions of your graphics and follow the instructions in the tutorial, you’ll be able to have retina sprites. As far as other graphics go, just follow the same logic you did with the iPhone4.

    @Damir: Yes, Image Groups can be inserted into display groups… they just can’t be inserted into other Image Groups (and display groups can’t be inserted into image groups).

    @David: To accomplish that, you’ll probably need to set up a sprite listener so you can detect when the sprite is ready to go to the next frame, and then set the timeScale accordingly.

  26. Nate Johnson says:

    @Jonathan Beebe
    Maybe I am misunderstand, so I apologize in advance if so. My thought was that we need a sprite sheet for the non-retina iPhones, @2x for retina iPhones and iPad 1/2 and now a third @4x for iPad 3. @2x looks great on the current iPads, but I think it will look blurry on the new iPad 3.

    Take a look at this thread, near the bottom. My thinking is along the same lines that the sparrow framework is doing for @4x resolution:

  27. Jonathan Beebe says:

    @Nate: I get what you’re saying now. Yes, you’ll need to have all those assets available if you want your app to be universal and compatible with everything. My previous response was in the case you were building an iPad-only app. So for a universal app, you’ll simply need to specify the image file suffixes in your config.lua.

    More info here:

  28. Nate Johnson says:

    @Jonathan Beebe
    That makes perfect sense. Thanks so much!

  29. Brent Sorrentino says:

    Awesome additions! Quite a load to handle, in truth, but our apps will be better off for it after implementing these new APIs.

    One suggestion I have with the new Sprite API (which was also lacking in the original) is a read/write parameter for the “direction” of the “bounce” sequence. Perhaps it returns “1” when going forward or “-1” when going backward.

    An example of this usage is this:

    Let’s say I have a series of 10 player ‘walking’ frames, and another sequence of ‘walkingWithSword’ frames. I absolutely don’t want to attach or append a separate sword image on top of the player and move/track it along with the player… that’s tedious and unreliable IMHO. I would much rather have a new sequence with a sword added (graphically) that MESHES with the previous sequence, i.e. the leg/arm animations stay in proper sequential order when the sequence is switched!

    Now, let’s imagine both of these animations follow the “forward” looping pattern: frame 1 to 10, 1 to 10, 1 to 10, etc. If I need to change the visual from ‘walking’ to ‘walkingWithSword’ mid-stream (say it occurs at frame 6) then it’s easy enough to do this:

    1) read current frame from ‘walking’ sequence… it’s frame 6
    2) change sequence to ‘walkingWithSword’
    3) force-set this new sequence to begin animating at frame 6, so the animation “meshes” (no skips!)

    Consider this in “forward” frame-numeric order:
    ‘walking’: 1, 2, 3, 4, 5, 6…
    (app changes animation at frame 6)
    ‘walkingWithSword’ = 6, 7, 8, 9, 10… 1, 2, 3, 4, 5, 6, 7, 8, 9, 10… 1, 2, 3 (etc.)

    BUT, this only works if the sequence is going “forward”! Unless this has been changed in the new API, any new sequence starts playing in a *forward direction*, even if it’s a “bounce” sequence.

    So, consider a similar sequence in “BOUNCE” frame-numeric order:
    ‘walking’: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 … 9, 8, 7, 6 (etc.)
    (app changes animation at frame 6 on the *backwards* bounce cycle)
    ‘walkingWithSword’ = 6, 7, 8, 9, 10 … 9, 8, 7, 6, 5, 4, 3, 2, 1 … 2, 3, 4

    OOPS! The new sequence, ‘walkingWithSword’ begins at frame 6, but it’s going in the wrong direction! Instead of logically progressing back to frame 1, it starts the new sequence in a *forward* direction, incorrectly returning to frame 10 before the bounce-back happens.

    Thus, a simple (hopefully simple for Ansca) addition of “spriteObject.sequenceDirection” would solve the problem nicely. Upon sequence change, we could read the direction of a “bounce” cycle, similar to reading the current frame, then SET that direction on the new sequence so the animation meshes perfectly. This could even be done internally and automatically, but I think some users might not prefer this behavior and thus it should be optional.

    Any thoughts Jonathan? I have currently “solved” this issue by duplicating several frames in my image sheet so I can just use a “forward” sequence setting, but this obviously adds more frames, and thus more texture memory, to my app.

  30. Brent Sorrentino says:

    My other huge “wish” for the new Sprite API would be this:


    It’s probably a long shot, and maybe not useful to all developers, but it would be cool to have an app-wide method to pause ALL sprites, similar to “physics:pause()” for the physics system.

    Currently, I place every animating sprite (a reference to it) into a table, then when I pause my game I loop through the table and pause each sprite individually. This works fine but it seems inefficient and somewhat bothersome. It also opens up potential errors, i.e. ensuring that only *playing* sprites are inserted into the table, non-playing sprites get removed from the table (on the fly), etc. etc.

  31. Jonathan Beebe says:

    @Brent: All great suggestions. I suggest you submit it as a “feature request” on the bug report form so that the requests don’t get forgotten. I like your idea of being able to query the sequence direction, because since these updates are all about preserving texture memory, that would alleviate users from having duplicate/reversed sequences.

  32. Hmm… does anyone know how to properly remove a sprite built this new way when it’s inserted into a classic displayGroup? It would be very helpful. I know there are tutes coming up but if someone knows… don’t hide the knowledge please! πŸ˜›

  33. Yups, didn’t saw the previous comment and answer from Jon, sorry!!! I’ll just wait πŸ˜‰ That’s what happens when you have a website opened for a couple of days without updating xD

  34. Damir says:

    I have a problem with the new API while the old API is working perfectly.
    Here is my scenario.
    I have a man which consist of 4 parts: body, head, hair and limbs.
    Only limbs are animated (7 frames). The man is a display group.
    In the old API all parts are sprites and they scale perfectly.
    In the new API the static parts (body, head, hair) are normal display objects

    body = display.newImage( imageSheet, 1 )

    and the dynamic part is a sprite

    limb = display.newSprite( imageSheet, sequenceData )

    The problem is the sprite (limb) is 1/2 size it should be πŸ™

    I am using dynamic content scaling – letterbox.
    The spriteSheet file is generated with TexturePacker and I am using the oldStyle for options (because TexturePacker does not yet support the new one).

    Any idea what went wrong?

  35. Damir says:

    The sprite size is not 1/2.
    If I put

    limb:scale( 1, 1.8 )

    I get about the right size.

    Seems like the new API scales the sprites differently than images for content scaling – letterbox.

  36. Kawika says:

    I’m looking forward to multiple examples of proper implementation of these items! Great Job ANSA!

  37. Brent Sorrentino says:

    I’ll post a feature request as you mention, for the ideas I suggest.

    On another note, I’m very confused about the usage of “dynamic” Retina sprites. If we define the width and height parameters in the “options” of the imageSheet (required), how does that work in accordance to the width and height definitions of “newImageRect()” ? We need to define both in each API (it throws an error otherwise), so should these values just be the same?

    Hopefully you can create some actual coded examples of these APIs soon… in the meantime, thanks for the documentation you’ve already provided here. I’ll tinker around with it more tonight, and maybe it’ll make sense.

  38. Jonathan Beebe says:

    @Damir: I don’t think the dynamic image resolution works properly when using the “old-style” backwards compatible data method, because the previous sprite API had no built-in support for dynamic image resolution, which is probably why you’re experiencing issues. The new sprite API didn’t add anything new to the old API, so if you need to take advantage of some of the newer features, you’ll have to switch to the new data formats.

    Also, sprite trimming/cropping is not yet supported, so that could be a cause for problems if your implementation uses that as well.

  39. Jonathan Beebe says:

    @Brent: When you define the width/height via sheetContentWidth/sheetContentHeight in the options table, that is referring to the *entire* image sheet file (with all of your frames). When you specify the width/height when using display.newImageRect(), you are only specifying the content width and height of the single *frame* you are referring to.

    And once again, the sheetContentWidth/sheetContentHeight params correspond to the 1x size version of your image sheet file.

  40. producerism says:

    It would be soooo great if we could specify a number of frames for time instead of (or better yet, in addition to) milliseconds.

  41. Brent Sorrentino says:


    Thanks as always for your help. So when I opt for dynamic images (static or animated), the standard “width” and “height” in the “options” table are ignored, and superseded by “sheetContentWidth” and “sheetContentHeight”? If frame width and height are defined in “newImageRect()” then those 2 sheet-defined parameters seem redundant in the options table. Am I correct about that?

    Also, your notes say that image sheets MUST be in the Power of 2… but my initial tests show image sheets working in “odd” dimensions also. This is just very initial testing however: simple static frames pulled from a non-complex uniform sheet. I’m really hoping that we aren’t forced into Power of 2, because it’s not always convenient. If I have a sprite whose frames really *must* be 560 pixels, not 512, to render in the size I truly desire on screen, upsizing every frame to 1024 adds considerable empty space to my sheet, which defeats the core efficiency purpose of this API. πŸ™‚

    If I understand correctly, it’s the *sheet* dimension which are supposed to be Power of 2, not each frame necessarily, but this has still presented some problems and complexity in my testing, specifically in fitting my existing images into this new Power of 2 “rule”.

  42. Jim says:

    Brent: Unfortnately this is almost certainly an OpenGL and/or hardware limitation. Power of 2 textures are par for the course even on next-gen consoles. Someone smarter than me can describe the reason why it’s faster to process 512×256 images vs odd sizes…

  43. Thanks for this great tutorial! I have a question: As an addition, would it be possible and make sense for Corona to support for us to change the “image” property of a body during run-time after the object was created… and then for Corona do an invisibly behind-the-scenes expansion into image sheet magic workings when this happens (provided the image resolution remained constant)?

  44. Nate Johnson says:

    What I plan to do with images is the following, and maybe this will help alleviate the powers of 2 worry. I plan to maximize an image sheet, maybe 1024×1024 or 2048×2048 and put everything on it. Everything being all character animation frames, title screen graphics (words for the title, start and credits buttons, background images, tiles, etc). There is no rule saying that an image sheet is for one set of sprites and you need another one for the next set. If you can fit all of your graphic assets on one image sheet, you can load many sprites and other images for your games from that one sheet and really maximize how OpenGL processes graphics.

    If I am mistaken, please correct me.

  45. Nate Johnson says:

    I’m going to try to take a shot at explaining dynamic image resolution as I understand it. If anyone sees any error, please speak up.

    First you need to specify in your config.lua file the resolutions you support. I support non-retina iPhone as the default. Then I support retina, iPad1, and iPad2 (2x), and will support iPad3 retina (4x). See the example config.lua below.

    From now on in your code, program for the 1x (non-retina iPhone) versions of images when you need widths and heights. Also, set the image sheet’s content width/height values for the 1x version of the sheet (see below) for a 512×512 sheet. Then you need two more image sheet files. Here are the three you need.

    sheet.png at 512×512 pixels
    sheet@2x.png at 1024×1024 pixels
    sheet@4x.png at 2048×2048 pixels

    Corona will now load the right sheet and squeeze the pixels for the proper screen automatically. Also, powers of 2 are very important to optimize OpenGL’s pipelines.

    — config.lua
    application = {
    content = {
    width = 320,
    height = 480,
    scale = “zoomEven”,
    fps = 60,

    imageSuffix = {
    [“@2x”] = 2,
    [“@4x”] = 4,

    — Some other lua file
    — Properties when loading a sprite sheet
    sheetContentWidth = 512
    sheetContentHeight = 512

  46. fito says:

    Awesome tutorial and great improvement!
    So old-style trimmed spritesheets created with texturepacker won’t be useful anymore until ansca adds trimming support??
    That’s bad for me, i have huge spritesheets with tons of small frames, and need to trim them in order to save space.
    When will trimming be supported? Because if not i’ll have to stick to the old and deprecated spritsheet API (then continue using SpriteGrabber).
    Anyway, thanks for the cool tutorial, it was really informative and i’m glad to know this part is being improved!

  47. Brent Sorrentino says:

    @Nate Johnson,

    Good advice; I’m sure this is what Ansca had in mind (putting lots of images on a single large sheet) for efficiency. I fully support that concept.

    Where it starts to confuse me, with this “power of 2” thing, is how to use those principles with sprites. It’s very easy to “cherry pick” a single frame from an imageSheet using the slightly more complex (but still sensible) ‘frames’ notation, where you define X, Y, width, and height for a frame. When it comes to sprites however, I don’t see any mention of how to accomplish this.

    Let’s take a simple example which actually resembles my game. I have 16 total frames, currently arranged on my sheet in 2 rows of 8 across. For sake of discussion, each frame is exactly 100×100 pixels. So, 100 x 8 means the first “row” is 800 pixels across… inconveniently between the two Power-2 numbers of 512 and 1024. So what do I do? No arrangement of these frames will bring the sheet to a Power-2 number, no matter how I shift them around.

    If I add empty space to the right of these frames, so the sheet adheres to 1024 across, then frame #9 will be blank… Corona doesn’t know to “wrap” to the next row, as far as I can tell… and without the ability to set an X and Y position of the first frame in a sequence, I can’t see a viable solution here.

    I suppose the “solution” is to add empty space around every frame, making them all 128×128, thus 128 x 8 across = 1024. But then, that sort of defeats the core purpose of all this optimization, because fewer images will fit on a sheet and I’ll likely need more sheets (or bigger sheets). It’s certainly fine for smaller image frames, but if frames are much larger, i.e. 600×600 pixels, then “padding” them in 1024×1024 really adds a bunch of wasted space (and let’s be honest, 600 pixels for an animation frame isn’t theoretical anymore, considering the huge resolution of the iPad3).

    Hopefully there’s a viable solution to this which simply isn’t clear to me based on this initial documentation. I know Jonathan can’t write every detail and usage examples for every case in this initial blog post. πŸ™‚

  48. Bogdan Vladu says:

    While updating LevelHelper to support this new api i discovered that display.newMultiSprite
    is causing error – attempting to perform display.newMultiSprite a nil value.
    Other then that its good to see this. I cut down a lot of LevelHelper code with this new api.
    Please fix display.newMultiSprite soon.

  49. Brent Sorrentino says:

    @Nate Johnson,
    Your explanation of “retina” dynamic images seems 100% correct, from a setup standpoint. The problem is that it assumes the most basic setup, which many developers (myself included) don’t use. A few points…

    1) I don’t design for old iPhone3 resolution and scale up. I actually design for closer to iPhone4/iPad and scale *down* for the old devices (yes, this is absolutely possible in Corona’s “config.lua”; the scale ratios don’t need to begin at 1 and go up, you can enter decimals for the scale ratios if you wish).

    2) Even if I configured from low-to-high, there are simply too many screens and configs available in the hardware world. An iPhone4 might be exactly 2x an iPhone3, but an iPad2 (height) is 1024 to iPhone4’s 960, thus 1:1.067 ratio. The iPad3 (2048) to the iPhone3 (480) is actually 1:4.267, not a simple 1:4. Enter Android devices into the mix, with their “stretched” taller screens, and the formula gets really complex. If I truly want to design images optimized for multiple devices, which I do, then rarely will this adhere to a simple 1x, 2x, 4x progression.

    The point is, each developer chooses a config setup for his/her needs and the desired target devices. Dynamic images can be suited to fit most of these cases, but if we are *forced* to use “Power of 2” for everything… as in, the app simply won’t work unless we do, or the sprites become garbled… then this becomes not just a limitation, but a show-stopper for me. I already have considerable assets designed for my app, and they can’t just be doubled or halved by this “rule”. Please say it ain’t so Jonathan…

    I apologize if my tone has become snippy, but I’ve been wrestling with this all morning and am now stumbling on “what next?” with this new API.

  50. Nate Johnson says:

    The documentation for config.lua mentions that it picks the closest scaling factor, so it doesn’t need to be an exact 1:2 or 1:4 ratio. That said, right now I am just focusing on iOS… if I were looking at Android, it would be much more difficult to generalize as I am doing. Also, I have had to do special things to make sure game objects that need to rest on the bottom of the screen are adjusted for an iPhone 4 vs iPad because of the different heights.

    On the power of 2 thing, I’m just not seeing the problem, but maybe I am not getting it either. Why not have a sheet that is 1024×1024. Use the top left part of it for 8 sprite frames that are 100×100. And then another different 8 sprite frames that are 100×100 right under the first, etc. Then like you said, there is that extra 224 pixels on the far right edge. Use that for a different asset. With the new API, I believe we can specify exactly where each frame is located, so it doesn’t matter if there is extra room – granted this makes laying out and finding the coordinates of frames a bit tedious but I think the performance gains are worth it. I could even see laying out an image that is 500×224 on that extra space. Then when you load it with newImageRect you rotate it -90 degrees so that it is orientated correctly in the game.

    My apologies if I’m not understanding your questions. I’m trying to learn how this new stuff works as well πŸ™‚

  51. Steve says:

    I have a few problems with the new build ( 761 )…

    – I can confirm that spriteInstance:removeSelf() or display.remove( spriteInstance ) does indeed crash the app or the simulator.

    Problem 1: Having created an imageSheet object for game sprites [ used texturepacker and ‘old-style’ sprite data that texturepacker also exports ] when I create a sequence for animated coins thus:

    local seqData = {
    name = “glint”,
    frames = { 1,4, 5, 7, 6 },
    time = 100,
    loopCount = 1

    local coinsprite = display.newSprite( imageSheet, seqData )

    so far so good… images in sheet are 64 x 64, but when I position and add them to the display they are 128 x 128 [ and I havent scaled them in any way at all! Nor is the display group scaled at all ].

    It seems to me to be a bug, it doesnt happen when I create a newImage( imageSheet, N ) [ N being the index of the image I want ]

    Problem 2: You will notice that my seqData contains an animation that should be played once only, and it does. . . .but when I try to play the same sequence again sometime later, it never plays the animation [ I want my coins to glint intermittently at random intervals, so the animation has to be one-shot ]. It was working perfectly well using movieclip but that doesnt support the use of imageSheets, so cant use it.

    coinsprite:setSequence( “glint” ) coinsprite:play()

    sometime later, triggered by a performWithDelay() thats way longer than the animation would take to play out, I call it again

    coinsprite:setSequence( “glint” ) coinsprite:play()

    This does not animate the sprite again….:-/

    Oh and can I point out that the ‘time’ field in the sequence data is incorrectly documented. . . it is not the time between frames in ms. . .its the time the ENTIRE sequence takes to play. . πŸ™‚

    So are these issues with the new sprite API or am I doing something wrong? I really dont want to hack movieclip.lua to use the new imageSheets πŸ™‚

    The new features [ imageSheet, imageGroups, the new sprite API ] are great and will lead to performance improvements but they currently seem to be a bit buggy and dont work as advertised πŸ™‚

  52. Damir says:

    Can someone confirm this is not working ?

    spriteObject.frame = 1 // <– this is not working

    This should "reset" the animation to the first frame and show it.
    (working in old API, only the syntax is spriteObject.currentFrame)

  53. Jonathan Beebe says:

    Quick update regarding sprite removal bug: We’re working on it and the fix should be checked in soon (so keep an eye on the daily build logs)

    Also, the “power of 2” issue with the OLD sprite API has been fixed and checked in, so that’ll be in the *next* daily build. Keep in mind that the NEW sprite API still has the power of 2 limitation.

    @Damir: You should be able to just call spriteObject:setSequence() (with no arguments) and it should bring you to the first frame in the sequence.

  54. Brent Sorrentino says:

    *sigh*… to say that I’m “annoyed” would be a huge understatement… pi**ed off would be more like it. I’m now into my second paid year of Corona, and in the past 1.5 years I don’t recall one mention of this “Power of 2 rule” in any Corona documentation, blog post, forum post, etc. (and I read quite a bit of this content, always have). Sprites in the old API worked fine without it, I should note. Sure would have been nice if *somebody* at Ansca had mentioned that OpenGL “needs” Power of 2 for its pipeline optimization. You know, we don’t all troll around OpenGL forums reading up on the engineering behind it. I know some here will say “you should have known this rule” but I doubt I’m alone on this issue.

    Anyway, I’m now facing an overhaul of my entire game engine (90% done before this) and a vast amount of graphics for 3-4 different device configs, all because suddenly we are boxed into this Power of 2 thing. I know in the end my app will be considerably better off for it, and faster, but I’m not pleased about 1-2 weeks of overhaul for a new sprite/imageSheet API.

    Jonathan, I continue to appreciate everything you do for Ansca and helping out the community, but you guys really need to get your documentation in order and keep it updated. This isn’t something we should just be learning about now. I believe you guys are located in Palo Alto; hire a couple Stanford interns to keep up on this, I’m sure they would welcome the opportunity to be part of a local tech company. Please pass this suggestion on to Walter and Carlos.

  55. Jonathan Beebe says:

    @Brent: The power of 2 requirement with the old sprite API was a bug that was introduced with these new changes—it’s now fixed and will appear in the next daily build. So once that build is posted, you’ll be able to continue using the old sprite API without your image sheets needing to be power of 2. The brand-new sprite API *does* have the power of 2 limitation, but that is something new that was introduced with this blog post.

    As a reminder these new features that come out with the daily builds are features that become available as soon as they are pushed in. Unfortunately, as early adopters, if you choose to download daily builds you might run into some early bugs with new features, and that allows us to catch/fix them before the feature is released to the public.

    But as another reminder, you shouldn’t have to redo your entire engine once the next daily build gets posted, as it fixes the power of 2 bug with the OLD api, which was a bug that was introduced with these new changes. But for future reference, anything you do with the NEW api will require your imagesheets to be power of 2 dimensions.

  56. Brent Sorrentino says:

    Thanks Jonathan,
    I was blowing off a bit of steam there, but in the end this isn’t as horrible as I thought. After punching alot of numbers into my calculator, I discovered that about half of my current dynamic images can be “re-factored” into Power of 2 sheets, without me remaking them all in Fireworks. The beast’s burden of the work will actually be putting individual images into image sheets, which I would have needed to do regardless of any Power 2 rule.

  57. Steve says:

    Regarding Image Sheets:

    in the ‘Complex’ image sheet options that are passed to specify layout of the individuals frames, I do hope that those parameters are the only mandatory ones and that tools like TexturePacker are free to add parameters such as ‘name’ as this would make it so much easier to associate a named frame with an index, via a table associated with an imageSheet that converts ‘named frame’ to an index.


    local options = {
    frames = {
    { name = “frame1” , x = nn, y = nn, width = ww, height = hh },
    { name = “frame2” , x = nn, y = nn, width = ww, height = hh },
    { name = “frame3” , x = nn, y = nn, width = ww, height = hh },

    from that I can build an associative array that i can use to create the frame I want.

    local asprite = display.newImage( imageSheet, indexTable[“frame1”] )

    So I never have to rememeber that ‘frame1’ is index 1. And it also means that the imported data from texturePacker or other tools can change all it wants and the code would still work πŸ™‚

    Can it be confirmed that x, y, width, height are the minimum and not the only parameters that are set in the imageSheet options table. Thanks.

  58. @Damir – I can confirm that spriteObject.frame = 1 is not working.

    Also, calling spriteObject:setSequence() does not reset the sprite to the first frame.

    The sprite animations are only playing the first time through. If spriteObject:play() is called a second time, the last frame of the sequence continues to be displayed making it appear as if nothing is happening.

    Calling spriteObject:setSequence() with or without a name param first does not affect this or reset the sprite. Also, NOT calling spriteObject:setSequence() doesn’t help either.

    It seems that once the sprite animation is finished, nothing is working to reset it. The last frame of the sequence continues to be displayed no matter what.

  59. David says:

    I have a sneaking suspicion that the new imageSheets are not compatible with the 3rd party Director Class. Whenever I try to change scenes after using an imageSheet / Sprite, Corona totally crashes and I get this error, even if I manually remove the imageSheet and Sprite:

    /Applications/CoronaSDK/Corona Terminal: line 9: 4627 Bus error: 10 “$path/Corona Simulator” $*

    Is anyone else experiencing this problem?

    Anyway, I will try to switch over to the new Storyboard API and see if that fixes it. I should switch over anyway, I suppose.

  60. fito says:

    My previous reply was lost between all these power of 2 comments ¬¬ and i really need an answer, so i’ll copy it here:

    Awesome tutorial and great improvement!
    Old-style trimmed spritesheets created with texturepacker won’t be useful anymore until ansca adds trimming support??
    That’s bad for me, i have huge spritesheets with tons of small frames, and need to trim them in order to save space.
    When will trimming be supported? Because if not i’ll have to stick with the old and deprecated spritsheet API (then continue using SpriteGrabber).
    Anyways, thanks for the cool tutorial, it was really informative and i’m glad to know this part is being improved!

  61. Arthur says:

    What are your recommendations for a tool to build image sheets?

  62. Brent Sorrentino says:

    A few more observations so far…

    1) It appears that “spriteObject.timeScale” is no longer working, to speed up or slow down a sprite animation on the fly. Will this be implemented into the new API, or something similar? I suppose it’s possible to create separate sequences that animate faster or slower, and switch them when needed, but “timeScale” was much easier.

    2) In the notation on the “time” parameter for sprites, it says that this is the time *between* frames, but my testing seems to indicate this is the *total* time of the entire sequence… that’s how the old API worked. Can somebody confirm this?

  63. @Brent – I think the old API time param was the time between frames. The new appears to be total time of sequence.

    Old API – I had a 16 frame sprite and time set at 50ms = 800 total ms for sequence

    New API – Same sprite, same settings ran so fast you couldn’t see it. I’m assuming it had to be because the 50ms setting was now total time.

    Changed it to 800ms and it ran too slow. Finally settled on 400ms for new API and now it’s *almost* the same as the old API. So I figured (old API time setting x number of frames)/2. However, this does not work with other sprites. Each seems to have it’s own ratio of old time setting to new time setting.

    Have not messed with time scale on either the old or new API.

  64. bvac says:

    Jonathan, I’m pretty sure the answer to this is “no” – but can imagesheets be used for masks?

  65. Jonathan Beebe says:

    Here’s a quick update for everyone:

    The power of 2 restriction for the new API has been removed, and all associated issues (with both the old and new api) has been resolved. Please download build 2012.264 or later for best results. That build also fixes the crashing issue that occured when removing sprite objects.

    @fito: Sprite trimming/cropping still works with the old API. In fact, anything that worked previously using the old api will still work. The new API, while improved, hasn’t quite caught up in every area just yet—stay tuned.

    @bvac: I’m sure what you’re asking is, can “frames” within an image sheet be used for masks, and that is no. You can use the entire sheet as a mask, though I’m pretty sure that’s not what you’re trying to do.

  66. bvac says:

    @Jonathan, correct, fortunately that’s not a terrible trade-off. Second question, can imagesheet frames be used for widget images like button states?

  67. Tom says:

    Three simple questions

    1) adding trimming and cropping is this a matter of few next builds or another month or two ?

    2) what about adding name to the frame and by name instead by frameID ? This is quite none productive.

    3) in my understanding any tool for exporting sprite should have option to set position of image for even number (8, 10,140, not 21). When image is scaled down to SD quality then position of the image in the file is not corrupted.

  68. Build 764 – Have not changed any code. spriteObject:setSequence() now works to reset sprite to first frame. However, calling spriteObject:play() after this does not play the animation again. Instead of being stuck on the last frame of the sequence, it’s stuck on the first.

    Also, spriteObject.frame = 1 does not work once the animation has completed. In fact, once the animation has completed spriteObject.frame returns 1 even if sprite is displaying the last frame of sequence.

  69. @RestlessNativeGames I second that, having the same issues here.

  70. Bulba says:

    I read that the property spriteObject.frame is Read/Write so I’m thinking that

    spriteObject:setSequence( “mySequence” )
    spriteObject.frame = 3

    should show the 3rd frame in mySequence.
    I’ve tested it but it seems it always shows the first.
    Any help on this please?
    How can I jump (without launching the sequence) to a given frame?

  71. Just to point out the obvious… Build 765 did not change anything/fix the issue from my last post.

  72. StefanHQ says:

    Asking again, will there be support for rotated sprites?
    This feature is standard in other api and allows better packing of the image data if it a lot of rectangluar objects.

    No need for free rotation (which should be nice) but just the option to pack image better by rotating it 90deg in the packed sheet and the rotate it back to its original state in the Corona ImageSheet api.

  73. Damir says:


    if you change sequences do you have to pause the previous one ?


    limb:setSequence( “walk”)

    limb:setSequence( “stand”)

    Is the limb:pause necessary ?

    Seems if I call it I can’t make the sprite to animate anymore…

    Wouldn’t the syntax


    be more intuitive ? (that is how it works in the old API + spriteGrabber, only its called playClip)

  74. Bob Dickinson says:

    The sprite event listener functionality does not appear to work with new ImageSheet sprites (I get a “began”, which is new and not documented, but no other events). I reported this as a bug.

  75. Bob Dickinson says:

    (FYI, using build 762 and 765)

  76. Yagiz says:

    Would someone explain how display.newMultiSprite( [parent, ] sequenceData ) works? Imagine I have these images: img0.png, img1.png, img2.png

    How do I do this?

  77. Nicky.B says:

    Posted this in the forum but really need an answer since my game is based around this.

    Is it possible to change the frame on a display.newImageRect?

  78. Kandya says:

    Using the new API I’m loading sprites just fine (using the old style data method) but nothing is appearing when I test on devices (iPad 1, iPhone 4)

    There is nothing in my code bar the examples above – I’ve stripped it all down as Director was also choking trying to load this particular screen – could I be missing something obvious? Everything is perfect in the simulator…

  79. Particle Candy has been updated to version 1.0.22 to support the new image sheet API.

  80. Mau says:

    What’s the new equivalent for MySprite.currentFrame?

    The above samples show how to define a frame to display when creating a new sprite, but not how to set the current frame for an existing one.

    Did I miss something..?

  81. Wilson says:

    I wrote a import module for the free Sprite Sheet Packer for Windows that makes making ImageSheets from individual image files a one-stop-shop …


    Forum Post:

  82. Bulba says:

    Apparently the insert function doesn’t work on image groups for the new sprites.

    This works:
    local myImageGroup = display.newImageGroup( imageSheet )
    local mySprite = display.newSprite( myImageGroup, imageSheet, { name=”myseq”, start=1, count=1 } )

    This doesn’t work:
    local myImageGroup = display.newImageGroup( imageSheet )
    local mySprite = display.newSprite( imageSheet, { name=”myseq”, start=1, count=1 } )

    This also means that there is no way to reparent a sprite from a “legal” image group to another “legal” image group.
    It seems a bug… or is it meant to work this way?

  83. Build 766 is supposed to fix the stucked sprite animation but I still have noticed some stucked animations (less than before but still there) and also some animations that don’t play to their last frame, if you’ve seen the jump power indicator in ChocoRun, sometimes (that’s the weird thing, just sometimes) it doesn’t fill the full circle and stops one frame before.

    I hope this is fixed soon and we can release a new update, but you’re getting there so… Thanks Ansca! and keep up the good work πŸ˜‰

  84. Jonathan Beebe says:

    @Alejandro: That sounds really strange. We aren’t able to reproduce your issues, so could you please submit a bug report with an isolated test case, and then send a link to your ticket to jonathan [at] We definitely want to get those issues fixed.

    @Everyone: I updated the blog post to included updated information about the new “Sprite Listeners” (which currently only have a “began” and “ended” event.phase), and also updated the spriteObject.frame info to reflect that it is “read-only”.

    I’m moving this comment thread to the forums because it’s getting to be pretty lengthy, so please post anymore issues you’re experiencing on the new thread:

    Also visit the thread to see a list of issues that we are currently working on before submitting any new ones.

    Thanks a lot for your help everyone!