Posted on by

Today’s tutorial covers how to implement animated sprites and use the related APIs. While this might seem like a rehash of previous tutorials, several key improvements have been implemented since the current sprite system was introduced earlier this year. In addition, many developers are still confused about how to implement sprites in Corona because, in fact, there are two approaches leading to a similar result:

  1. The old (and now depreciated) sprite.* library.
  2. The current sprite APIs that work cohesively with image sheets and the display.* library.

While Corona is technically “backwards compatible” with the depreciated sprite.* library, we strongly encourage that you use (or migrate to) the current sprite methods. If you haven’t implemented the current methods or haven’t ever used sprites in Corona, this tutorial will walk you through the process.

For those already familiar with basic animation in Corona, this tutorial introduces the full array of sprite event listeners and how to implement them.

Tutorial Contents

  1. Configuring a Basic Image Sheet or “Sprite Sheet”
  2. Defining Animation Sequences
  3. Declaring a Sprite Object
  4. Sprite Control Methods — managing playback and sequences
  5. Sprite Properties — accessing and setting various sprite properties
  6. Sprite Event Listeners — detecting sequence events such as “ended”, “loop”, and “next”

Configuring a Basic Image Sheet or “Sprite Sheet”

What exactly is a image sheet? Imagine it as a sheet of paper on which you draw the individual frames for your animated object(s). Other technical terms include texture atlas, image map, or sprite sheet. In Corona, we’ll simply refer to it as an image sheet, because its usage is not limited to either static or animated objects — you can, and often should, use image sheets for both purposes: static images picked from a portion of an image sheet, and animated sprites utilizing multiple frames from a sheet.

Detailed technical notes and usage examples for the graphics.newImageSheet() API are located here, but in this tutorial we’ll discuss how to use image sheets for animated sprites.

Pictured below is a sample image sheet for a running cat. If you want to use this image sheet to follow through the entire tutorial, you can copy the hi-resolution version from here. This sheet consists of eight “frames” in a specifically ordered  sequence. By default, the animation will begin at the top-left frame, proceed to the next frame (to its right), wrap to the next row when it reaches the end of the current row, and finally stop (or repeat) when the entire sequence is complete.

Let’s proceed with how to configure this image sheet in Corona. First, set up an indexed table for a basic image sheet of uniform-sized frames. You can (and often will) set up an image sheet using frames of different sizes packed in a tight, optimized arrangement (see documentation), but in this tutorial we’ll use a basic image sheet.


24 Responses to “Tutorial: Animated Sprites and Methods”

  1. J. A. Whye

    Cool tutorial, wish I’d had it a week ago! I was wanting an “onComplete” for when a sprite sequence was done playing and when I didn’t see that, I ended up using timers. And while it worked, it’s the kind of thing that can break if I add more frames to the sequence, etc.

    Now that I know about sprite event listeners I can do things the “right” way. :)

    Jay

    Reply
    • lalala

      hm, yes. but be cautious with that:

      the sprite.’ended’ event occurs at the BEGINNING of the last frame of an animation. not at the end.

      I don’t know if that’s actually meant to be that way. I find it very unintuitive.

      Reply
  2. Chris Leyton

    Always enjoy a good tutorial – particularly one on sprites. However I do feel that this is going over the same turf again.

    Perhaps we could have a further tutorial on this subject – check out this guy’s blog posts, really enjoying how he organises his sprites and tackles a tricky subject like splitting up sprites:

    http://www.ardentkid.com/blog/2011-07-11/dynamic-character-sprites

    Perhaps we could get him to do a guest post on the subject.

    Reply
  3. Brent Sorrentino

    Regarding dynamic sprite sheets… let’s assume you have the following scaling set up in your “config.lua” file:


    application = {
    content = { fps = 60, width = 704, height = 1024, scale = "letterbox", xAlign = "center", yAlign = "center",

    imageSuffix = {
    ["@1"] = 1.0,
    ["@2"] = 2.0,
    ["@retina"] = 4.0
    }
    }
    }

    You’d then create 3 separate image sheets based on this scaling. If, for example, your “@1″ image sheet is 1024×1024 is total dimensions, your sheets would be sized/named as follows:

    mySheet@1.png = 1024 x 1024
    mySheet@2.png = 2048 x 2048
    mySheet@retina.png = 4096 x 4096

    Now, in terms of using these sheets dynamically for sprites, you must always declare the 1:1 or “@1″ sheet dimensions (1024 x 1024 in this case) as the parameters for “sheetContentWidth” and “sheetContentHeight” when you declare the image sheet parameters.

    The Corona sprite engine will use these parameters to both choose the correct sheet for the animation (depending on the device) AND it will adjust the frame width and height parameters that it selects from the sheet accordingly, behind the scenes.

    Hope that helps!
    Brent

    Reply
  4. Ian

    When I add “mySpriteListener” function, why does it take a few seconds for the cat sprite to start running at the “time=250″ speed?

    Reply
  5. Brent Sorrentino

    Hi Ian,
    The “fastRun” sequence doesn’t begin until the “normalRun” sequence completes 4 full cycles, as dictated by “loopCount=4″ in that sequence… and also the fact that the listener is waiting for the “ended” signal, which occurs after ALL FOUR loops have completed. If you don’t specify a loopCount (or if you set it to 0, which will loop forever), you’ll never get an “ended” phase. If you want to detect the end of just ONE sequence in a forever-repeating animation, you can sense the “loop” phase which is returned when a sequence starts over at the beginning.

    Reply
  6. Leonard

    I copied code from “Putting it Together” paragraph into main.lua file. I also copied PNG file into root folder by dragging it into Macbook download folder, and renamed it to match file name in the code. I noticed that code does not work. I understand it probably is still missing most of what complete main.lua needs to have to actually work. Am I correct?
    My concern, probably shared by other readers, is that only experienced Lua developers are intended audience of this and similar blogs. Those new to Corona still do not have a good source of information. It would be great if someone took initiative to focus on new users and explain how Sprites and other features work, vs. providing not too closely related extracts from different files and programs, that still may need major additional code to make it work.
    I would appreciate if someone could suggest good source of beginner level tutorials on Sprites and similar topics. I purchased Corona subscription, but do not see much difference in access to any good tutorial with or w/out subscription. Online blogs and tutorials are mostly bits and pieces from advanced developers exchanging tips and advice and marketing their services, but there is very little focus on helping others. Besides one person from Australia, all materials are very unstructured and confusing. Good fundamental teaching environment is still waiting to be introduced to Corona community.

    Reply
    • Brent Sorrentino

      Hi Leonard,
      What is the error you’re receiving when you test your project? It’s probably something small but important.

      I sympathize with your situation, but it’s a “fine line” with tutorials. This one, in particular, was viewed as far too simplistic by many Corona developers… a “re-hash” if you will. Most developers seem to crave something new and more advanced, especially in this weekly tutorial arena.

      For beginners, I can recommend Brian Burton’s excellent e-books. They are geared toward getting you up-and-running with Corona, and Dr. Burton is a trusted authority in the field. Yes, they are sold at a price, but it’s a reasonable price and worth the investment if you’re getting a headache from browsing endless forum posts, third-party blogs, and random code snippets.

      His website is linked below. If you have questions, please contact Dr. Burton personally. He is prompt to respond and will certainly respond to you whether his books might meet your particular needs as a new user to Corona.

      http://www.burtonsmediagroup.com/books/

      Best of luck!
      Brent Sorrentino

      Reply
  7. saiphan

    hey, i am having a problem with the coding for this tutorial.
    first thank you for uploading thise but i cannot see the code writen to add in “putting it together” the line is just empty.
    second:
    it gives me an error of a “bad argument” to ‘newImageSheet’ (table (options) expected).
    i tried to implement a local function named options and changed the “sheetData” to “options” too based on – graphics.newImageSheet() – on the website. but still giving me the same error. what do i do wrong? please help.

    Reply
    • saiphan

      ok nvm i managed to make it work using several other references on the site. thanks anyway. it seems that unlike as3 u need to declare the function before calling it what caused the problem to begin with.

      Reply
      • Brent Sorrentino

        Hello saiphan,
        Good to hear you figured it out. Also, thank you for telling me that the code example(s) were missing. Apparently something became corrupted in the previous Gists and they weren’t appearing. I replaced them, so now you can see the code examples specific to this tutorial.

        Best regards,
        Brent

        Reply
    • Brent Sorrentino

      Hi Jerry,
      Yes, TexturePacker should handle this fine, but you’ll need to take the data that it generates (without any of the “sourceX” or “sourceY” stuff, if you have it) and put that frame info into your sprite setup.

      Brent

      Reply
  8. Michael

    Fantastic work- as usual- folks! I just spent two days trying to force Lime and Tiled to work with sprites and then in 5 minutes got things working after reading this page! To infinity and beyond Corona!

    Reply
  9. Hector

    Long time ago i created a class that is really similar to this, with almost the same methods plus some more. After read the article, for the moment i prefer to use mine because if i have not understood bad, with this is only possible to create sprite atlas where each frame has the same size than the rest, no? and for me is essential trim frames (usin texture packer) and not to lose lot with empty space.

    Reply
  10. Max

    Hi, if got a problem with the scale of the images.

    local options = {
    width = 192,
    height = 64,
    numFrames = 4,
    sheetContentWidth=192,
    sheetContentHeight=256, }

    local Sheet = graphics.newImageSheet( “img/mysheet.png”, options )
    local sequenceData = {
    { name = “health0″, start=1, count=1, time=0, loopCount=1 },
    { name = “health1″, start=1, count=2, time=100, loopCount=1 },
    { name = “health2″, start=1, count=3, time=200, loopCount=1 },
    { name = “health3″, start=1, count=4, time=300, loopCount=1 }
    }

    local healthSprite = display.newSprite( Sheet, sequenceData )
    healthSprite.x = 320
    healthSprite.y = 26
    healthSprite.width = display.contentWidth/6
    healthSprite.height = display.contentHeight/18
    healthSprite.alpha = 0.75
    local statusBar = display.newGroup()
    statusBar:insert( healthSprite ) –”statusBar” is a display group

    –healthSprite:setSequence( “health” .. 3 )
    –healthSprite:play()

    After I insert setSequence or play() Corona changes the scale of my imagesheet image back to its original size.
    I wonder what’s wrong with that? I just want to keep the size I had(means related to display.content) .
    I hope there is an easy way to fix this. I can’t believe I have to make a lot of different scaled images for this.
    Thanks for your help.

    Reply
  11. Max

    I’ve…
    —-
    Okay. Found a way for myself. I used :scale and it does work as I wanted.
    healthSprite.width = display.contentWidth/6
    healthSprite.height = display.contentHeight/18
    This doesn’t seem to work with the sprite animation. If it’s a bug, fix this please.
    As suggestion you could a :scale reference to the API.

    Reply

Leave a Reply

  • (Will Not Be Published)