config-featIn this week’s tutorial, we revisit the “Ultimate config.lua” which introduced a more functional config.lua file — one that helped many developers convert their letterbox apps into full screen apps. This time around, we’ll aim to make it better.

1. Simplification

If you recall from the original file, each device “group” was separated into code blocks. For example, the Android block of the file targeted two different sized screens, those with an aspect ratio of less than 1.72 and those with greater. That meant on these devices, it still was not a precise fit. Rethinking the Android portion lead to this simplification:

else
   application = 
   {
      content =
      {
         width = 320,
         height = 320 * display.pixelHeight / display.pixelWidth,
         scale = "letterbox",
         fps = 30,

         imageSuffix = 
         {
            ["@2x"] = 1.5,
            ["@4x"] = 3.0,
         },
      },
   }
end

With a simple calculation, we can determine the exact height of our content area based on a 320 pixel wide area.

A very helpful Corona developer “@aukStudios” has proposed a better way to handle the config.lua — instead of having all of those separate code blocks for different devices, why not just compute them all? The answer, after several revisions, is the following refactoring of the previous version.

--calculate the aspect ratio of the device:
local aspectRatio = display.pixelHeight / display.pixelWidth

application = {
   content = {
      width = aspectRatio > 1.5 and 320 or math.ceil( 480 / aspectRatio ),
      height = aspectRatio < 1.5 and 480 or math.ceil( 320 * aspectRatio ),
      scale = "letterBox",
      fps = 30,

      imageSuffix = {
         ["@2x"] = 1.5,
         ["@4x"] = 3.0,
      },
   },
}

All of the separate if statements for different devices have been eliminated down to this one simple block of code.

Let’s consider the logic. For base 320×480 devices, we set a width of 320 and a height of 480. For “tall” devices like the iPhone5 or most Android devices, we want to keep the content area at 320 wide but automatically calculate the height. Using 320 and 480 (1:1.5 ratio), if the aspect ratio is greater than 1.5, we can assume it’s a tall device and make the width 320. For the height, we calculate the height as 320 × the aspect ratio.

The iPhone5 is 640×1136, so we can do this math (height divided by width):

1136 / 640 = 1.775

1.775 is greater than 1.5, so we calculate the height to be 320×1.775, or 568, the correct value.

The iPad, in contrast, is a “wide” device, so to keep things to scale, we want the 480 content height to span the height of the screen, with the letterbox regions on the left and right. Mathematically, it works out to 360 points wide:

1024 / 768 = 1.333333
480 / 1.333333 = 360

1.333333 is less than 1.5, so we calculate the width (360) and for the height, we use the fixed value of 480. For simplification, we round off the calculations to whole numbers.

2. Moving Beyond 320×480

NOTE: With Apple releasing the new iPhone 6 and 6 plus, they have made it clear they want to continue to use a a point system based on 320 points.  Corona SDK widgets (widget.* library) are designed to work in a 320 point space, including widget.newButton.  If you want to use the new Adaptive content area, or if you want to use widgets, you should continue to use 320×480 if you use a simple content area.

We’ve always suggested 320×480 as the “standard” content size, because in days past, that made sense for the original iPhone, iPhone3, and iPhone3GS screen sizes. When the iPhone4 was introduced, it was easy to just double that content size to that device’s 640×960 screen size (and it worked reasonably well on the iPad as well). However, when Apple released the Retina iPad, and other high-definition tablets and phones entered the market, we suddenly found the need to have three versions of all of our app graphics: a “legacy” set for the older devices, a “normal” set for the ~640 pixel wide devices, and an “HD” set for the newest devices.

Today, there are even more high resolution devices which we may want to support, like 1080p TVs and the latest class of tablets which are pushing the HD concept even higher. Fortunately, this means that there are fewer of the small screens to support.

In addition, the “one screen pixel = one content area pixel” concept, from the 320×480 iPhone days, doesn’t make sense anymore, considering the vast array of screen sizes on the market (Samsung alone produces almost 30 different screen sizes).

As a developer, now may be the time to reconsider the old standards and come up with something that makes “doing the math” a bit easier, and one with that represents modern devices. Some developers began doing this quite some time ago.

One suggestion for a convenient and modern content area would be 800×1200. This maintains the core 1:1.5 aspect ratio as 320×480, but it makes the numbers and screen positions conceptually easier to work with. The center point is (400,600) vs. (160,240), 80 pixels is 10% of the content width, etc.

As you probably know, Corona SDK will scale your content up or down as necessary. At the same time, it will dynamically and automatically select the proper resolution images if you set up dynamic image scaling properly.

Using this new content area size of 800×1200, we’ve dropped the “legacy” image set entirely, opting for two suffix schemes that cover the vast majority of modern devices. And thus, the “refactored” config.lua becomes:

--calculate the aspect ratio of the device
local aspectRatio = display.pixelHeight / display.pixelWidth
application = {
   content = {
      width = aspectRatio > 1.5 and 800 or math.ceil( 1200 / aspectRatio ),
      height = aspectRatio < 1.5 and 1200 or math.ceil( 800 * aspectRatio ),
      scale = "letterBox",
      fps = 30,

      imageSuffix = {
         ["@2x"] = 1.3,
      },
   },
}

In this example, devices with a screen width greater than 1040 pixels will use the larger “@2x” image set, while smaller devices will use the regular non-suffixed images.

In Summary

As you can see, a logical, easy-to-understand content area is essential to multi-resolution development, whether you’re working on a game or a utility app. Since devices will continue to diversify and expand to even higher resolutions, it may be time to adapt to a config.lua that works well with today’s devices while providing some “room to grow” as well.

  1. @Rob

    So is the last code block provide above supposed to completely replace your “Ultimate Config.lua”.

    Also for the:

    imageSuffix = {
    [“@2x”] = 1.3

    Do we still make our @2x image double in size or are they to be 1.3 the size of the 1:1 images?

    Thanks
    Rob

    • Thats the whole thing. Pretty amazing huh?

      Yes, your @2x graphics are double the 1x graphics. They are what would have previously been your @4x and your previous @2x are now your normal ones. The 1.3 doesn’t have anything to do with the actual graphics size, it just sets the point at which Corona will pick up the larger @2x graphics instead of the 1x graphics.

      In the days of old when we only had a 320×480 and 640×960 device, it made sense to say @2x was double and that scale factor was 2.0. But when the Kindle Fire and Nook came out as well as more larger Android screens, a 600×1024 device was < 2.0 compared to 320px, so they would use the small images.

      When we wrote the original ultimate config.lua, the 1.5 was picked so that anything less than 480px wide would use low res images and 480 and up would use the @2x images (and 960 or wider @4x). Now with the 800×1200 base content area, you really only need the high res images on screens over 1000 pixels wide (well 1040 in this case).

  2. Wow, this is really nice. I popped it into my current project and it looks like it will ‘just work’… just to confirm, could we conceivable only have two versions of our graphics or do we still need 3? (base size, @2x, @4x)?

  3. There are still a lot of devices which are below “current @2x”.
    This would mean, that you would load and scale twice as big images to display on them.
    Smaller screen USUALLY means lower spec devices, and this means that you may run out of memory or your game will work considerably slower.
    I’ve given my users options to change the resolution of the graphics on Android, simply because depending on resolution is not enough. Take a look at modern tablets. Some Chinese manufacturers tend to put 720p or even 800p screens into their tablets, while providing little memory and slow processor. Loading graphics on such device takes ages and the game simply shutters when there’s something going on. Loading lower resolution graphics, although changes the crispiness of your game, will allow players to have a fluid animation, thus a better gameplay.

    Although I think that this move is a way to go for iOS, for Android I would add a @low postfix with [“@low”] = 0.6 option.

    Anyway, I would not remove the ability for the end user to choose what kind of graphics do they want.

    As a simple example, I will give you Samsung Galaxy Tab 10.2. It has a 1024×800 resolution, which in my config will put it by default into a HD range. Graphics look amazing, but when I cast few spells on screen, game will shutter. However, when I change in settings to use the HDPI image set, the game still looks great, but the memory usage is way lower and game won’t shutter in crucial moments.

    Just a food for thought when you develop for Android.

  4. This is something that I think is worth taking a look at. However as krystian mentioned above, some Android devices do have underpowered hardware which might require special attention.

    Also, for Apple, if we decide to set our deployment target to iOS 5.x (or even 6.x now), I’d say we still need to include the 320×480 graphics since most of the devices running those iOS versions will very likely have non-retina screens.

  5. Rob: Thanks again for a great tutorial. However, one picture is worth a thousand words.

    I would sure like to see some images with tutorials and accompanying code.

    Thanks!

  6. Rob,

    I would like to just confirm the two sets of graphics now. For a background image file we would now have:

    1x = 640×960
    @2x = 1280 x 1920

    And these are the sizes of just the backgrounds.

    If you don’t mind me asking, if we were going to put a basic graphic on the screen to use as a general “button”. How would you size these types of objects now? I have been using 50×50 and 100×100 for these types objects. Would you suggest going up and using 100×100 as the base object and 150×150 for the @2x objects?

    Thanks

  7. Krystian and Ingemar, looks like the paragraph about older devices got missed along the way. Clearly, if you need to support smaller screens, which are typically on lower power devices, making this move may not be as prudent. It’s perfectly fine to build this with a 400×600 content area and still include 3 levels of graphics, or engineer a -low prefix. The lower end tablets are problematic because you want you app to look good, which means larger images, but you have to manage their performance too, which means an app that doesn’t look as good.

    The beauty of this config.lua is a) you don’t have to use it. b) you can feel free to adapt it to your needs.

  8. Rob. Sorry for any misunderstandings.
    I fully support what you’re attempting to do here, and I’m going to use with it myself as it looks good.

    I just wanted to raise awareness that the default minimum deployment target for Corona is iOS 5, and if somebody decides to skip the low-end graphics, as in the last example, they might run in to problems unless they also raise the deployment target as well.

  9. I’m not sure why all this fuss about the config lua.
    What I do is simply set it up as 320×480, aligned top left, letterbox, and in main.lua I set global screenWidth and screenHeight values equal to the display.actualContentWidth and display.actualContentHeight (gotcha – you have to swap these values if running in landscape).

    That way you get your app with a minimum of what you specified (320×480 in this case), but always filling the screen and handling stretching regardless.

  10. Hi,
    Thanks for the tutorial!

    My feedback :
    Everything works fine with the corona simulator.
    But when I put it on devices, (I tested on iPhone 4, iPhone 5, iPad 2), it doesn’t work on iPhone 5.
    It is as if the iPhone 5 was considered as an iPhone 4.
    So images and background do not occupy all the space available on the iPhone 5 screen.
    Thank you for your help :)
    Olivier

    • You still have to provide the required Default-568h@2x.png file. It’s case sensitive and must be exactly 640px wide and 1136px high. No variations. It must be in the same folder as your main.lua. If you do not provide this, Apple assumes you are a 3.5″ high device and not a 4″ high.

  11. So if I use this config.lua, what size does my background images need to be so that they fill the whole screen with no black borders on any device?

    I tried 800 x 1200 images liked explained here but on the Galaxy S3 I get black bars on top/bottom and on the iPad I get black bars on the sides.

    I load the image like this:
    local background = display.newImageRect(“Background.png”, 800,1200);

    What am I missing? Thanks!

  12. just to be clear the base image should be 800px X 1200px and the @2x should be double that 1600px X 2400px… and because these images are big you won’t have to go bigger than that.. ex @4x right??

  13. Hi @Skaflux and @Antonio. I guess we didn’t enforce the concept that needed to have read the previous “The Ultimate config.lua” blog post where we talked about how to manage backgrounds (i.e. base images).

    There is a long standing formula that’s been recommended in the forums for making your background as wide as your widest device and as tall as your tallest device based on the content area you are using. The original blog post had an image with it that draws how each device uses this magic formula. At that time, the core screen was 320×480. A device that’s the same shape as HDTV (16:9) needs a 320×570 background. A more wide device like the iPad needs a 360×480 background. Therefore you can use a single 360×570 to cover the content of any device who’s aspect ratio is less than 16:9 which gets most devices.

    Now when we change this to a 800×1200 content area, you actually need a 900 x 1425 background. Now on all devices, some of this image will “bleed” off the screen so you have to make sure there are not critical parts of the background that will be in these “bleed” areas. The @2x version would be 1800 x 2850. Yes, 2850 is greater than the 2048 max texture size that some devices have, but if your device needs the @2x version it likely supports a larger texture size or Corona SDK will scale it down to 2048 and then stretch it back out (not optimal, but it’s better than stretching a 900×1425 to a much larger size.)

    • So just to bring this full circle for those that want to still support low res devices (e.g. iPhone 4), would the following be recommended as settings and associated file sizes? Note in the code I used 450, 712.5 for the newImageRect size. I’m assuming that’s okay and would make the scaling for the more common 2x more accurate?

      Config:

      –calculate the aspect ratio of the device:
      local aspectRatio = display.pixelHeight / display.pixelWidth

      application = {
      content = {
      width = aspectRatio > 1.5 and 400 or math.ceil( 600 / aspectRatio ),
      height = aspectRatio < 1.5 and 600 or math.ceil( 400 * aspectRatio ),
      scale = "letterBox",
      fps = 60,

      imageSuffix = {
      ["@2x"] = 1.5,
      ["@4x"] = 3.0,
      },
      },
      }

      Background Files:

      background.png (450×713)
      background@2x.png (900×1425)
      background@4x.png (1800×2850)

      Loading image in code:

      local bg = display.newImageRect("images/background.png", 450, 712.5)

  14. Hi,

    I’m trying to get the best dimensions of a background image that would work across all major tablets (using also the @2x). I tried using the dimensions proposed here (1425×900, 2850×1800 @2x) but when I view in the simulator it seems that most representations (iPad, iPad Retina, Nook, etc.) end up squishing the image to fit the content area.

    I thought this was not supposed to happen when the scale mode is set to “letterBox”. I should never see squishing, rather the best attempt to fit the image in the content area with the bleed areas potentially bled off screen.

    Any implementation details would be appreciated.

    Cheers, Ken

  15. Can you post this request in the forums please? I would like for you to post some code where you are loading your backgrounds in, and it’s better to help you there than in the blog comments.

    Thanks
    Rob

    • I was in the middle of writing the post to the forum when I realized that the issue has to do with the width & height values I’m passing to the newImageRect method to display the background image.

      I had just been using display.contentWidth & display.contentHeight which was always “fitting” the image to the full display size when I guess I need to either pass the actual values of the image (and then code the position – center, etc.) or calculate new values for these parameters based on how I want the image to adjust to the size of the device’s screen while maintaining the original aspect ratio.

      If there are any good Corona shortcuts for any of this let me know otherwise I’ll proceed as I described.

      Thx! Ken

      • I always do:

        local background = display.newImageRect(“images/background.png”, 1425, 900)
        group:insert(background) — if you’re using storyboard
        background.x = display.contentCenterX
        background.y = display.contentCenterY

        • Thanks for this. I’ve been experimenting with various combinations of settings between the config file and the dimensions used for the newImageRect method and this seems to do the trick (and, yes, I’m using the storyboard API).

          Cheers! Ken

  16. “In this example, devices with a screen width greater than 1040 pixels will use the larger “@2x” image set, while smaller devices will use the regular non-suffixed images.”

    So iphone 4+ won’t use @2 image anylonger, right ?

      • That means that images are no longer optimized for low rez devices, since 320*480 and <1040 devices will use the same images.

        Most of new low cost android devices are 320*480, and it's pity to drop optimization (previous ultimate config.lua).

        • If you feel it’s important to still support 320×480 devices, by all means do so. You can also still provide half scale images and still take advantage of the larger content area.

      • Thanks for the reply, but just for confirmation, would the config.lua file look like this:

        –calculate the aspect ratio of the device

        local aspectRatio = display.pixelHeight / display.pixelWidth
        application = {
        content = {
        width = aspectRatio > 1.5 and 320 or math.ceil( 480 / aspectRatio ),
        height = aspectRatio < 1.5 and 480 or math.ceil( 320 * aspectRatio ),
        scale = "letterBox",
        fps = 60,
        imageSuffix = {
        ["@2x"] = 1.3,
        },
        },
        }

        and what would the exact dimensions be for the backgrounds?

        thank you for your support!

        • The only thing I would do differently is add back support for @4x graphics since you are keeping the smaller screen sizes by doing this, so your imageSuffix block would return to:

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

          but the 320’s and the 480’s are in the right place.

        • This will likely remain the case for a while. Widget heavy apps should use a content area that’s the traditional 320×480 scale (the version at the top, not the 800, 1200 version).

          Rob

  17. I couldn’t get the whole scaling to work, when using a larger then default 320×480 resolution as base and defining graphics for hdpi and small iphone. For iphone retina and ipad it would always use the smaller than standard assets.
    I had to add [“”] = 1 to image suffix definition. Now it works fine.

  18. Great post. I am using 640×960 for my base in the config file and have had major issues with table view widget. Does this widget and the others require a 320×480 base in the config? Do you think this will change soon since people are moving away from this size?

  19. The tableView widget should be able to be sized to any size you want. The only thing that may have scaling issues are the scroll bars. The pickerView does not scale.

    However, it might be easier to do a 320×480 content area if you are going to be working with widgets.

    Rob

  20. Hello Rob, im new to corona, i recently purchased Corona Basic, Im currently learning to use the software, if i use this method, what would be the best way to place objects(sprites)?, using x y coordinates. or placing objects based on screen width, height. for example (player.x = display.contentCenterX+100), im trying to get everything to look the same on every device.

    • Using this method, if you want something a distance away from the top or left edge, you would just use the number of pixels (well technically points since we are not thinking about device pixels) away from that edge.

      If you want something a distance away from the right or bottom edge then you will do something.x = display.contentWidth – someDistance or something.y = display.contentHeight = someDistance.

      If you want to have an object some distance from center (meaning the edges don’t matter), then you would use the contentCenterX and contentCenterY +/- value.

  21. This looks great, unfortunately I can’t quite get it to work, some images seem to be completely off center when inside groups on different devices.

    Would it be possible for anyone to link to a working sample code that includes a main.lua, image.png, image@2x.png and the config file that would scale it correctly for each device.

    That would really help.

    Thank you

    Sat

      • Hi Rob,

        Thanks for the Reply, on second thoughts I realised what was happening, the code above works great, problems of scaling to fullWidth of the screen only occurred when using sprite sheets. So I just split the large spritesheet up into multiple separate file images which solved the problem.

        Thanks for the post!

        Sat

  22. Okay, so you would think that this would be simple and easy to understand by now, but it just isn’t.

    I’m confused by the idea of having the content area be 800×1200 (portrait mode), which will require backgrounds of 900×1425 and 1800×2850 (for 2x mode).

    If I am running that on an iPhone 5 series, which has pixel dimensions of 640×1136, then that means that that the background will be scaled up by 1.40625 to go from 640 to 900. That means that the height will be scaled from 1136 to 1598. Which means that the stated sizes of the background will not work. Bars will appear at the top and bottom.

    Isn’t that correct?

    • Oh, never mind. That was a math error. I should have been adjusting 640 to 800, not 640 to 900..

      Math. Never something one should be doing on a Friday night after drinking wine. :)

  23. So since the Corona content width and height values will change depending on the current hardware, I assume you should never set the y coordinate value of any on-screen object by using a literal numeric constant…..only calculated values…..is that correct?

    In other words:
    never do: obj.y = 30
    always do: obj.y = someCalc

    If I have that correct, then what method do most people refer for “someCalc”…..do you anchor UI flow from the top, center or bottom

    • If you want something Y points from the top, you can use a literal constant: obj.y = 30
      If you want something X points from the left size you should use a literal constant: obj.x = 30
      If you want something Y points from the bottom you can use: obj.y = display.contentHeight – 30
      If you want something X points from the right edge, you can use: obj.x = display.contentWidth – 30
      … assuming 30 points is how far away you want it from the edge. Likewise if you want it some distance away from center, you can do obj.x = display.contentCenterX + distance (or – distance or contentCenterY for up and down from center).

      What are points? When you use a defined content area, in our example above, 800×1200, that’s the scale you’re going to have on an iPhone 3gs even with its 320×480 screen. Everything in Corona is measured in content area dots or points, not pixels since pixels imply the device. Because this config.lua calculates the width and height based on the aspect ratio of the device, your content area may not be 800×1200 but 800×1280 for tall devices, or more like 900×1200 for an iPad.

      Rob

      • Could you also use obj.x = display.contentWidth*0.2
        So this would just be a relative value and be exactly the same for each device?

  24. I use your first method with the following resolutions so older devices are still supported:

    360×570
    720×1140
    1440×2280

    How will this look on newer (future) devices like the Galaxy S5 with a 1440×2560 resolution? Will it stretch? Do I need to introduce other resolution images? What do you recommend?

    • It’s going to rez up on a 1440×2560 a bit. As resolutions creep up, there will need to be sacrifices made. You can add an @5x but that means bigger app bundle sizes or you can start with bigger images and have more down scaling, etc. There isn’t a right answer right now but look for the balance that works for you.

          • I could also replace the 4x with 5x since memory usage for this resolution (1800×2850 vs 1440×2280) will be the same if I’m not mistaken.

            imageSuffix = {
            [“@2x”] = 1.5,
            [“@5x”] = 3.0,
            },

            As you described earlier:

            600 / 320 = 1.875 –Kindle Fire & Nook
            640 / 320 = 2.0 –iPhone 5
            768 / 360 = 2.13 –iPad
            800 / 320 = 2.5 –Kindle Fire HD / Nexus7
            1200 / 320 = 3.75 –Kindle Fire HD 8.9
            1536 / 360 = 4.26 –Retina iPad

            5x images on 1080p phones and higher resolutions:

            1080 / 320 = 3.375 –HTC One
            1200 / 320 = 3.75 –Kindle Fire HD 8.9
            1440 / 320 = 4.5 ###### For the new 1440×2560 resolution ######
            1536 / 360 = 4.26 –Retina iPad

            So same memory usage but better quality images?

  25. Hi Rob,

    I’m trying using your method

    bg.jpg (360×570)
    bg@2x.jpg (720×1140)
    bg@4x.jpg (1440×2280)

    With this config.lua

    –calculate the aspect ratio of the device

    local aspectRatio = display.pixelHeight / display.pixelWidth
    application = {
    content = {
    width = aspectRatio > 1.5 and 320 or math.ceil( 480 / aspectRatio ),
    height = aspectRatio < 1.5 and 480 or math.ceil( 320 * aspectRatio ),
    scale = "letterBox",
    fps = 60,
    imageSuffix = {
    ["@2x"] = 1.5,
    ["@4x"] = 3.0,
    },
    },
    }

    and in the main.lua :

    local backok = display.newImageRect( "bg.jpg", 360, 570 )
    backok.x = display.contentCenterX
    backok.y = display.contentCenterY

    So why my background isn't scaling up on Ipad retina, Ipad, Iphone4 and 5…?
    Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>