Tutorial: Techniques for swapping images

Share on Facebook0Share on Google+5Tweet about this on TwitterShare on LinkedIn7

Sometimes, the design of an app dictates the need for “image swapping” in which the developer needs to draw an image at a given location and then, after some time or some action, swap that image for another. Here’s a theoretical example:

But this is not how Corona SDK works as :swapImage() is not a built-in Corona method. When Corona builds an image, it has to read the file in from the app bundle’s file system, allocate texture memory for the image, render the PNG or JPG compressed data into four color channels, and return a display object for you to work with. To “swap” that image, Corona would need to destroy the object in question and create a new image. Effectively, it’s the same amount of work as required in this example:

In this scenario, you’re probably not planning on using the first image again soon, since the original image was destroyed. The advantage to this method is that it minimizes texture memory, since only one of the two images is in memory at once. However, if you want to get the original image back, you’re caught in this cycle of image loading and unloading over and over. In itself, this is an inefficient process that can impact performance. Thus, if you need to swap images more frequently, you should explore other techniques. Let’s look at a few options:

The 2-image swap

If you have two images, you can simply load them both, add them to a display group, and reference the images as parameters of the group. In this example we will use a typical touch handler and swap the image in the "began" phase of touch handler:

In this case, we load two images: redBall and blueBall. We position them at the same location, making one visible and the other not. We also set an attribute on the group (whichBall) so we know which is the visible image. Now for the touch handler:

Now let’s focus on the swapping code in the began phase:

If the touch begins, and the ball is red, we make that image invisible, make the blue ball visible, and note which is the “current” image. Because the move code is on the group, not the individual images, the images move together as a unit.

Fill swap

You can also take advantage of the graphics “fill” methods to swap images:

This method eliminates the need for the display group — just create the base image (in this case a rectangle the size of our images), position it, and fill it with the red image “paint.” Now, in the touch handler, which is now on the object itself since we eliminated the group, the code is a bit simpler. Just remember that t in this example is the event.target or the ball object.

Multi-image swap

Sometimes you’ll want to swap more than two images. For a game like Candy Crush or Bejeweled, you may want to have several images that occupy a spot on the screen and quickly change among them. In this case, we can go back to the group model, load all of the images into an array, and access them via their index number:

Here, we iterate through the ballImages table to create the display objects, storing them in the balls table as we go along, and make each one invisible. Then, we make the first one “current” and visible again. Now, to manage the swapping in a cyclical manner, we can execute this code:

Image sheets and sprites

While the above methods are all perfectly valid, using individual image files is not the best use of memory and load time. This is why we encourage the use of image sheets, in which you load a single image “sheet” containing all of the individual images, and load them from that sheet. Image sheets take a little more initial setup, but the the benefits are well worth it. Converting the above code to image sheets may look as follows:

From a code perspective, this is not much different from the array method above, other than the efficiencies gained from using image sheets — but image sheets are a gateway to an excellent way swap images: sprites.


Corona features a comprehensive sprite engine. While the name “sprite” may seem to indicate only an animated character or object in a game, you should consider it as simply a series of images which can be used for multiple purposes, including swapping images. Let’s look at the sprite-based version which builds upon the image sheet version above:

Like the version using graphics fills, we no longer need the display group since the sprite is, by definition, a multi-frame object than can reside in any group by itself. Once the image sheet is set up and the sequence defined (all eight frames), simply call display.newSprite() with the image sheet and the sequence data. Next, use the :setFrame() method to pick which frame to display and the sprite engine handles the rest — no need to make other images invisible as in some of the other examples.

In summary

As you can see, there are various approaches and methods to the “swap images” concept, and it depends on your needs and design specifics as to which method is most suitable.

Share on Facebook0Share on Google+5Tweet about this on TwitterShare on LinkedIn7
Rob Miracle

Rob Miracle creates mobile apps for his own enjoyment and the amusement of others. He serves the Corona Community in the forums, on the blog, and at local events.

This entry has 13 replies

  1. Piotr says:

    Nice tutorial Rob. Is there a way to load fill from image sheet?

  2. Very, very cool! I actually needed this in my last project, but I’ll keep in mind for the next one!

  3. Damir says:

    What about performance? Which one is the fastest?

    E.g. sprite vs fill

    • Rob Miracle says:

      Sprites were engineered to be and efficient means of swapping images. I would say the fill method is probably quick enough for smaller images, but you probably wouldn’t want to try and replicate sprite animations with fill though.

  4. Robi says:

    Can you add a method which can made a transtion between the images?

    • Rob Miracle says:

      I’m not sure how to use a transition with the G2.0 fill method or the sprite method, but for the others instead of setting .isVisibile to true or falls, you would use two transitions:

      transition.to(balls[idx], {time=250, alpha=0})
      idx = idx + 1
      if ( idx > #balls ) then
      idx = 1
      transition.to(balls[idx], {time=250, alpha=1})

      Of course the objects that are not showing would need their alpha to be initially set to 0 and the one showing to 1.


  5. Greg says:

    Hi Rob,

    Excellent tutorial, many thanks!

  6. Hi Rob,

    There’s a standard way of cycling through things, which should be mentioned here as many programmers are not aware of the modulus operation and it’s uses.

    i=(i+1) % n, if you have the array beginning with 0, which is better for this reason
    i=i+1%n, if you have the array starting at index 1.

    Sad thing is, lua starts it’s arrays at 1 by default, so you normally have to use the latter alternative which is a pain in my eyes..

  7. rhann says:

    Hi Rob, I’m a beginner in lua because of our thesis project.. I’m having a problem in swapping scenes but if I use only 2 different scene it’s working but when I add more, it won’t swap.. here’s the code I’m using…

    local sheetData1 = { width=960, height=720, numFrames=4, sheetContentWidth=2048, sheetContentHeight=2048 }
    local sheet1 = graphics.newImageSheet( “spritesheet.png”, sheetData1 )

    — 2nd image sheet
    local sheetData2 = { width=960, height=720, numFrames=4, sheetContentWidth=1926, sheetContentHeight=1446 }
    local sheet2 = graphics.newImageSheet( “spritesheet2.png”, sheetData2 )

    local sequenceData = {
    { name=”seq1″, sheet=sheet1, start=1, count=4, time=2000, loopCount=0 },
    { name=”seq2″, sheet=sheet2, start=1, count=4, time=2000, loopCount=0 }

    local myAnimation = display.newSprite( sheet1, sequenceData )
    myAnimation.x = display.contentWidth/2 ; myAnimation.y = display.contentHeight/2

    — swap the sequence to ‘seq2’ which uses the second image sheet
    local function swapSheet()
    myAnimation:setSequence( “seq2” )
    timer.performWithDelay( 2000, swapSheet )

    I don’t know where to put the 3rd spritesheet.. hope to get an answer Thank you! 🙂

    • Rob Miracle says:

      Please ask this in the forums.


  8. du Chalard says:

    I have a probleme with swapImage:
    local yolo=display.newImage(“yolo0.png”,0,0)
    yolo:swapImage( “yolo1.png” )

    Runtime error
    c:\users\er\documents\corona projects\3 kings\constructanim.lua:139: attempt to call method ‘swapImage’ (a nil value)
    stack traceback:
    c:\users\er\documents\corona projects\3 kings\constructanim.lua:139: in function
    ?: in function [Finished in 17.3s]
    It’s make a long time i have this probleme, i use actualy .fill but the problem with “fill” it’s resize my image and it’s take quite a long time to do the fill for the mobile phone.

    • Rob Miracle says:

      Please ask this in the forums?


  9. C B Mishra says:

    can you please generate a function through which we can move a bitmap in matrix in android.