Posted on by

It’s Wednesday and time for another five frequently asked questions (FAQ).

Question 1

Should I use PNG or JPG image files in Corona?

Answer

The answer depends on the quality of the images you need and the size of your app package. Corona supports 32 bit PNG and 32 bit JPGs. PNG supports transparencies with loss-less compression where JPGs are compressed (lossy) but supports a wider range of colors. PNG files are generally a larger file size than JPGs for the same resolution. This can affect the size of your app package.

As for the amount of texture memory consumed, both PNG and JPG take up the same amount of openGL memory because the images are uncompressed when loaded into memory. You should also be aware that images are loaded into openGL memory in “powers of 2″ (2, 4, 8, 16, 32, 64, 128, 256, 512, etc.). This means if you have two images: 320×480 and 280×400, both images will consume 512×512 of texture memory. A 769×1024 image will consume 1024×1024 bytes.

Question 2

Why do I see “began” touch events but sometimes “ended” events are missing?

Answer

This is not a bug and you need to be aware how this can happen and how to handle the condition. There is a began and ended event for every touch. If you create a touch listener for a display object, you will generally get began, moved, and ended events when the object is touched. It’s also possible that the listener could be missing one or more of the events depending on how the listener is written and how the user touches the object.

The following code shows a simple touch listener for a circle object.


local circle = display.newCircle( 100, 100, 50 )

-- Touch listener
local function myTouch( event )
print( "Touch event = " .. event.phase )
end

circle:addEventListener( "touch", myTouch )

If the user touches and releases their finger on the circle, the listener will be called with began and ended events. If the finger is moved while touching the circle, moved events will also be seen.

Take the case where the user touches the circle and moves their finger off the circle and then releases the touch. The listener will get a began event along with moved events, but no ended event. The listener will not see this event because the end of the touch was not on the object.

So where did the ended event go? The answer is either another object’s listener; the Runtime touch listener or nowhere if neither of the previous listeners were defined.

This brings up the situation where a touch listener receives moved or ended events but no began event. The reason is because the touch event moved into the object or off an object and into the Runtime global touch listener.

If you need the listener to track all the touch events (from began to ended), call setFocus on the object.


local circle = display.newCircle( 100, 100, 50 )

-- Touch listener
local function myTouch( event )
print( "Touch event = " .. event.phase )

if "began" == event.phase then
display.getCurrentStage():setFocus( circle ) -- set touch focus on circle
event.target.focus = true
end

if "ended" == event.phase or "cancelled" == event.phase then
if event.target.focus ~= true then
return false
end
print( "Ended found" )
display.getCurrentStage():setFocus( nil ) -- clear touch focus
event.target.focus = false
end

return true
end

circle:addEventListener( "touch", myTouch )

The setFocus shown in the example is set during the began phase and locks the touch event to the object. This way the listener is called for all touch events for this touch, even if the touch leaves the object. setFocus is called again on the ended event to release the touch focus from the object.

You may have noticed the following code in the above example:
event.target.focus = true
This was added in the began phase as well as a test for the condition in the ended phase. This bit of code handles the case where a touch started (began) outside of the object but ended on the object. The focus flag is created for the object to indicate if the touch began on the object and to ignore it if it didn’t. You are free to add your own custom variables to display object to track things like this.

For more information about touches, see Tutorial: Detecting Touches in Corona.

Question 3

I’ve seen two different ways to define a function in Corona. Which way is correct and what’s the difference between them?

Answer

Functions can be created in two ways:


local function myfunc1()
print( "function = ", myfunc1 )
end

and

local myfunc2 = function()
print( "function = ", myfunc2 )
end

Both methods work in most situations. The second case doesn’t work when you need to reference the function name inside the function itself. This doesn’t work because the function variable “myfunc2″, is not created until the function has been defined. Where in the first case, the function variable, “myfunc1″ is created before the function is defined and therefore can be referenced within the function. If you run the above code in the simulator you will see in the first case the value of myfunc1 is defined as a function, but myfunc2 is nil.

“myfunc1″ function is equivalent to this:

local myfunc1
function myfunc1()
...
end

I prefer writing my functions as shown in the “myfunc1″ example because it seems more traditional to me. I also don’t have to worry about getting a “nil” value when referencing the function name inside the function. It should be noted that if you make the functions global (removing “local”), both functions work the same way.

Question 4

In config.lua I set my screen size to 640×960 (iPhone4) but my images are smaller on iPhone3. Why?

Answer

If you are using display.newImage to load images that are larger than the native resolution of the target device, the images will be scaled to fit the screen before they are “dynamically scaled” based on the width/height set in the config.lua file. For example, if you are trying to load a 600×100 pixel image onto an iPhone3 (320×480 screen), the image will be scaled down to fit the screen before being dynamically scaled. This causes the image to appear smaller on a iPhone3 when compared to the same app on an iPhone4. The solution is to either use display.newImageRect (and set the desired size of the image — 600×100 in our example) or use display.newImage and set the “isFullResolution” flag to true. This bypasses the image scaling based on the native screen size.

Note: There is a bug in display.newImage that causes images larger than 320×480 to be scaled down on the iPhone4. This happens whether dynamic scaling is on or off. This bug was fixed in Daily Build the 2012.788.

For more information see Dynamic Image Resolution.

Question 5

There has been a number of audio bugs in Corona with iOS 5. Why do you keep saying to file bugs with Apple?

Answer

Sometimes Corona bugs are caused by bugs found in the operating system. We try to work around the problems but the real solution is to get them fixed in the OS. There has been a few openAL audio bugs in iOS 5 that have been very hard to work around. We have tried to get the word out by posting messages in the forums and in replies to our support cases about filing bugs with Apple. The more users who file these bug reports means the more likely Apple will fix the problem. If nobody files these reports (except for Ansca), the problems may never get fixed.

You can find out more information and file Apple bugs here: Apple Bug Reporter.


Posted by . Thanks for reading...

14 Responses to “FAQ Wednesday”

  1. Darren Osadchuk

    The nil value problem with the second method of declaring functions can be avoided by forward-declaring:

    local myfunc2
    myfunc2 = function()
    print( “function = “, myfunc2 )
    end

    Reply
  2. Michael

    Thanks, Tom!

    There is no doubts that PNG and JPEG are equal in memory terms. But I heard that PNG is easier for iPhone to display and as result it loads faster. Is it true or not?

    By the way Apple Bug Reporter link is corrupted.

    Reply
  3. GreenCastle

    Re: Q2-
    A while back I submitted a bug report with a workspace that demonstrates the possibility for a Runtime only touch listener to not have a ended event. In a non-multitouch app, if you place your finger down, drag, touch a second finger, and release the first finger (while the second finger is touching), you’ll never get an ended event.

    Are you saying this is not a bug? I’m assuming there is no way to setFocus to Runtime.

    Reply
  4. Ken Cardita

    Tom,

    Thanks for the 2nd installment of FAQs. As I look towards the future where there are dozens of FAQ posts each with a number of questions, I think it will be tough to locate a particular question with them spread across multiple posts. Can I suggest the following

    In addition to the weekly posts can you maintain a SINGLE document with all FAQs in it , maybe organized by topic ?

    Thanks
    Ken

    Reply
  5. Tom Newman

    @Darren, yes defining the variable before creating the function does work. Most users don’t do that so it’s a good tip.

    @Michael, the PNGs are crunched by an Apple utility program before they are placed in the app package which does make them smaller and I’m sure optimized for loading. I’m not sure how the loading time or size compares to JPGs.

    @GreenCastle, all touches will have a Began and Ended event. If multitouch is enabled, you will have the events for each touch. If you only have one touch listener enabled, and that is a Runtime listener, it should receive all touch events. You can’t setFocus on a Runtime listener because there is no display object associated with it.

    @Ken, we started this feature to get a feeling for how useful this would be to users. The idea was to move the FAQs to a searchable area on our site if this proved to be a popular and useful feature.

    Thanks everyone for your comments and feedback.

    Reply
  6. Mo

    THANKS Tom! Fantastic FAQ’s Love it. I learn new things every time. We need a Monday, Tuesday….FAQ’s day…just kidding.

    Thanks again.

    Mo.
    (LairdGames)

    ps: + 1 for Ken’s idea

    Reply
  7. Antheor

    Very clear topic : I guess I have, at last, understood the setFocus thing :))

    Thx !

    Reply
  8. Sven.Lua

    I know it’s not easy to explain in some less words, but two facts about JPG and PNG are wrong:

    JPG “supports a wider range of colors” – in no useful sense this is true. It was true for GIF vs. JPG but not for PNG. (the opposite is true: PNG can support a lesser range of color – but that’s not useful for Corona on Apple devices – so forget it)

    “PNG files are generally a larger file size than JPGs for the same resolution.” Here the word “generally” should be changed to “mostly” – because “it depends on”…

    PNG is better (also in compression results) for simple looking images with less colors, less details, without photo like things, with hard contrasts like in comics (outlines,…), …

    JPG (with good compression) is bad for some of this things, because you see the compression artifacts also in lesser compression ratios.

    a cite from http://www.turnkeylinux.org/blog/png-vs-jpg

    “But also we’ve discovered small and simple images may actually compress better using PNG than JPG. It seems to depend on how much is “going on” in the image. PNG works best for vector type graphics with hard lines. JPG works best for anything with complex gradients (e.g., a photo).”

    What I should mention – for a lot of use cases the PNG version looks more clear, sharp and brilliant than a medium compressed JPG with it’s artifacts and color degrade. Think of these terrible screenshots in the android market.

    Sorry for my worried English

    Reply
  9. Mo

    Quick questions if I may about image size and the “power of 2″.

    1- Let say I have an image like 120×40. Would you just leave it alone OR make the canvas 128×64 and then center the actual image inside that new canvas size (so you can use image rotation and so on)? I even have the feeling that the canvas will need to be 128×128? I am not clear on that last point.

    2- Let say I have a @2x (for iPhone 4) image of size 250×26 and so the regular image (for iPhone say) will be 125×13. Other than the issue of power of 2, would the fact that the small size image cannot divided by 2 cause a Blury on the screen of iPhone 3GS say. I have heard that you need your image size to be divisible by two but I am not sure if that relates to the normal image or the @2x?

    Thank you and please keep those FAQ coming!

    Mo.
    (LairdGames)

    Reply
  10. Michael

    Hey, Mo!

    1. You don’t have to change anything in your files. Just keep in mind that every cross “power of 2″ size in pixels by one of the dimension will take twice memory. So, when you can choose size of the picture between 125×125 pixels and 130×130, it’s better to choose 125×125 cause it’s fit in 128×128.

    2. Not sure what you asking for. You have to create 2 files: image.png and image@2x.png. In the display.newImageRect you write the size of smallest one, image.png. For example you have image.png 125×13, and image@2x.png – 250×26. So, your code should be local img = display.newImageRect (“image.png”, 125, 13). Corona will do everything else for you and you will have crisp and sharp images on both iPhones.

    Hope it helps.

    Reply
  11. Mo

    Thanks so much Michael! Crystal clear on Q1.

    On Q2 I was only wondering if having a small image which dimension would not be divisible by 2 (like 125×13) would result into a blurred image. Maybe it is the @2x that should be divisible by 2 since if you have a @2x image of size say 249×53 then the small image will have a dimension of 124.5×25.6 which of course cannot really be rendered as is. Anyway I kind of remember something about having to be careful on the image size (in addition to the actual issue of file size) in order to avoid blurry images for being displayed.

    Thanks again Michael for taking the time. I appreciated it.

    Mo

    Reply
  12. Michael

    You’re welcome, Mo!

    Sure, it’s better to use even numbers of dimensions to avoid blur.

    Reply

Leave a Reply

  • (Will Not Be Published)