Today’s tutorial comes to you courtesy of Rob Miracle, a member of Corona Labs’ Developer Relations team. Rob has been a Corona developer for over 18 months and has released over a dozen titles using the platform.


A very common question people ask when developing mobile apps is, “How do I support all of these different devices?” On the iOS side alone, we now have three basic “shapes” that we have to deal with, in addition to various resolutions. Factor in Android and things become even more crazy.

Some screens are wider while others are more narrow.  If we take resolution out of the equation, its easier to visualize the screens. Corona makes it easy to take resolution out of the picture using Dynamic Scaling.  With Dynamic Scaling, you can use a common set of screen coordinates and Corona will automatically scale the text and graphics for different resolution screens.  It can scale upwards or downwards depending on your starting point.  It also can substitute higher resolution images when it needs to scale up. This is all managed by a Lua file in your project folder called config.lua.

Since available resolutions vary considerably, it’s helpful to use the same scale for each device.  It doesn’t matter if you’re on an iPhone 3GS at 320×480 or a Retina iPad at 1536×2048, the location (0,0) represents the top-left corner and (320,480), in vertical portrait mode, is the bottom-right corner. The screen center is (160,240).  Each point, in this case, is one pixel on a lower-resolution device like the 3GS, which has a native screen resolution of 320×480, while each point is four pixels on a Retina iPad. Don’t worry about the math — Corona will handle it for you.

Basic Screen Shapes

Consider this image at 360×570 in overall width and height. We are going to make our image backgrounds bigger than the physical screen. Why? Because we need to accommodate different devices.  The inner rectangle is a 320×480 block.  Parts of the image at the top, bottom, left and right will reside off screen. When we switch to a “tall” device like the iPhone 5 or most Android phones, it will use the full height of the image, but a portion of the left and right sides will reside off screen.  If you have an iPad that is closer to square shape, it will crop off the top and bottom area but use the full width of the image.  The portions that reside off screen are referred to as the “bleed area”, a term from traditional printing where ink would bleed off the edges of the page.

Now that we understand and can see, visually, how the background will be used, let’s set it up in your config.lua file. Since this is a standard Corona Lua file, we can use several API calls to accomplish the following:

  • read the pixel width/height of the device
  • use math for various calculations
  • read the device model number
  • perform string manipulations
  • use conditional “if-then-else” logic

iPad Configuration

The first thing we’ll do is determine if the device is an iPad.  We can get the model number of the device by using the following Corona API call.

system.getInfo("model")

Currently, if you’re testing on an iPad, it should simply return the string iPad, but Apple might change this in the future and return something like iPad Retina.  So, let’s use this information and set up an if statement to manage that block:

if ( string.sub( system.getInfo("model"), 1, 4 ) == "iPad" ) then
   application =
   {
      content =
      {
         width = 360,
         height = 480,
         scale = "letterBox",
         xAlign = "center",
         yAlign = "center",
         imageSuffix =
         {
            ["@2x"] = 1.5,
            ["@4x"] = 3.0,
         },
      },
   }

Using Lua’s string.sub() function, we read the device model and look at only the first 4 characters, in case Apple ever decides to tack something on the end. In this case we’re looking for iPad, and if that’s true we set up the application content table to include the width and height parameters of 360 and 480 respectively.  We use 360 because our sample background is 360 pixels in total width and we want it to span the full width of the iPad screen. Please note that the config.lua file always is always configured as if you’re doing a “portrait” app.  If you’re designing an app in “landscape” mode, you should still specify width and height in the portrait orientation — Corona will manage the translation for you.

With 360 as the width, now we need to calculate the height that will fit the iPad’s screen shape.  The iPad screen is 768×1024, or 1536×2048 for the Retina iPad (exactly double, thus the same ratio). First, divide 1024 by 768 to get 1.33.  Then, to get the height, multiply 1.33 by 360 for a result of 480.

1024 / 768 = 1.33  --screen ratio (height:width)
1.33 x 360 = 480

iPhone5 Configuration

This time we are only going to look at the first 2 characters of the model string.  Why? This catches both the iPhone and iPod Touch models! We also detect the actual pixelHeight of the devices — this display property is included in Corona build #971, so please download it if you haven’t already.  If the pixel height is greater than 960 (the height of an iPhone4) then we know the device is an iPhone 5 or latest-generation iPod Touch.   Since this is a 640×1136 device when we scale it to 320 pixels, its a 320×568 device.

As stated above, our preference is for the sample background height to span the screen height of the iPhone 5. The native height of the iPhone 5 screen is 640×1136. Since our “inner rectangle” on the background is 320 pixels wide, the math is simple:

320 / 640 = 0.5  --inner rectangle width / device pixel width = factor
1136 × 0.5 = 568  --device pixel height × factor = config.lua 'height' setting

Notice that our sample background image is 570 pixels in height. As such, a mere 1 pixel will “bleed” off the top and bottom of the iPhone 5 screen!

iPhone 3,4 and Older iPod Touch

Since we’ve handled the iPhone 5 above, any model string that starts with iP will be a traditional iPhone or iPod Touch with a screen size of 320×480 or 640×960. Conveniently, we can use the width and height of our “inner rectangle” in this configuration block: 320 and 480 respectively.

Android, Kindle Fire, and Nook

Finally, we need to separate the 16:9 Android devices from the 5:3 devices (Nook and Kindle Fire).  The 16:9 devices are at a 1.777:1 ratio. The Nook and Kindle Fire are closer to 1024×600 or 1.7:1, so we can use the pixelHeight and pixelWidth to calculate the ratio for the screen size.  If it’s greater than 1.72, we set up a screen similar to the 16:9 iPhone 5; if not, we default to something that fits those tablets better.

elseif ( display.pixelHeight / display.pixelWidth > 1.72 ) then
   application =
   {
      content =
      {
         width = 320,
         height = 570,
         scale = "letterBox",
         xAlign = "center",
         yAlign = "center",
         imageSuffix =
         {
            ["@2x"] = 1.5,
            ["@4x"] = 3.0,
         },
      },
   }

else
   application =
   {
      content =
      {
         width = 320,
         height = 512,
         scale = "letterBox",
         xAlign = "center",
         yAlign = "center",
         imageSuffix =
         {
            ["@2x"] = 1.5,
            ["@4x"] = 3.0,
         },
      },
   }

end

Important Notes

The complete file is rather detailed, but it covers most devices or comes very close.  The main things you need to remember:

  • On some devices parts of the background will be off screen, so don’t put anything “critical” in the bleed areas.
  • Objects positioned using fixed numbers like player.x = 64 and player.y = 64 will always be 64 points away from the top and left edges, but based on the device will be closer or further away from center.  Likewise, objects placed using the right and bottom edges will stay the prescribed distance away from those edges (player.x = display.contentWidth-64 will stay 64 points away from the right edge) but they will move closer or further from the center too. Objects positioned based on a center coordinate (player.x = display.contentCenterX+100) will stay in the same relative position regardless of the screen shape.

Dynamic Image Selection

Notice that each configuration block contains an imageSuffix table like the following:

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

If you’re new to Corona, this is how the SDK handles Dynamic Image Selection. For example, you don’t want to use the same image assets on a Retina iPad and an iPhone 3GS. Instead, you should create at least two different image sets to accommodate both “normal” and “Retina/HD” devices.

Each entry in the imageSuffix table consists of two parts:

["@2x"] =        --append this suffix to all images designed for those device(s)
(decimal value)  --scale factor that Corona uses to pick the proper assets

The first value can be named whatever is convenient for you, but it should be reasonable and convenient to append to each image file in that set. The second value is calculated using the following formula:

device width / config.lua 'width' = scale factor

If the scale factor on a particular device is greater than the number you specify for the entry, Corona will use those assets.

Instinctively, you might think that the following entries are logical:

["@2x"] = 2.0
["@4x"] = 4.0

Not so fast!  Inspect the following calculations, derived from our configuration file:

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

Notice that if you specify 4.0 as the scale factor for your Retina/HD image assets, the Kindle Fire HD 8.9 will not use those assets, because its scale factor comes in at 3.75 — and yet, you most likely want to use those assets on such a big, sharp display. Thus, in our configuration blocks, we have chosen the following values:

["@2x"] = 1.5,
["@4x"] = 3.0,

Effectively, this tells Corona to use the highest-resolution “@4x” images for the Retina/HD devices such as the Retina iPad, Kindle Fire HD 8.9, and the Nexus 10. For all other devices, it will choose the “@2x” images instead, conserving texture memory which is especially limited on mobile devices.

One last important note. To display this background, use a call to display.newImageRect() like:

local background = display.newImageRect( "background.png", 360, 570 )

The last two numbers, 360 and 570, indicate the image’s base “1x” width and height, but in practice you don’t need to include that version of the image in your compiled project unless you are targeting lower-resolution devices that require it. In the sample calculations above, the lowest-resolution target device(s) are the original Kindle Fire and Nook Color. For these and other devices in the “@2x” bracket, Corona requires a version at 720×1140. For those in the next bracket, it requires a “@4x” version at 1440×2280. In all cases, it will handle the substitution behind the scenes so you don’t have to worry about it.

In Summary…

This tutorial is rather detailed and comprehensive, and if you’re new to Corona it might seem like a lot to digest. However, the config.lua file we’ve outlined provides you with a pre-made, proven configuration file that is compatible with essentially all new and not-so-new mobile devices from the iPhone 3GS all the way up to the iPhone5, Retina iPad, Kindle Fire HD, and Nexus tablets. If you haven’t downloaded it already, please get it here.

  1. This is an interesting post because we’ve been doing things entirely differently, and I suspect this way might be a lot better. Our current way is just to only configure for iPhone 3GS resolution and then treat any letterboxing regions on devices with varying aspect rations as extra canvas for us to display non-essential game elements.

    One thing I’m wondering about is if you see changes in the physics engine behavior as you change the width/height for each device type.

    • Where some of your items are positioned will vary depending on how you place them and that could have some impact. If you think of a game like Angry Birds and if the sling shot and the Pig’s buildings are further apart or closer together it could effect how strong a projectile is when it hits the blocks. From that perspective, it could have an effect. But in this case build it so everything fits in 320×480 and center that display group and the rest of the screen is scenery.

      • Hello Rob,

        Could you explain me what is the best practise of preparing rest of resourses/images in this conception.
        Do i should start preparing images (sprites, sheets) for 2280×1440 and then scale them to 1140×720 ?
        What size of image i should define in this method:
        display.newImageRect( “pic.png”, size1, size2 )

        For example:
        i prepared following sprites:
        pic@2x.png (100×100)
        pic@4x.png (200×200)
        pic.png – i don’t need it
        When i create a object do i should use:
        display.newImageRect( “pic.png”, 50, 50 )?

      • Hi Rob,

        Here we are developing 12 games and planning to release them in single file. Now the problem is few games are in portrait mode and others are in landscape. But there is only one config.lua, were we have specified it as landscape, because of that portrait games are not working . So my question is that how to run both the modes using single config file. Give us some suggestions.

      • Hi,

        I always use 320×480 and it works fine in all android devices, I just have to keep in mind that my useful sceneario is 320×480 and to avoid blank spaces, I use a big background.

        In iOS I am having that problem, even though the image is so big, It shows two black spaces at both sides of the ipod. What can I do to make it work like android or even like the corona simulator? thnks in advanced.

        • It sounds to me like you’re missing the required Default-568h@2x.png file that iOS needs to identify your app as “Tall compatible”. This is a 640×1136 pixel, vertical image that has to be named exactly that and be in the folder with your main.lua.

    • If I understand you correctly we are doing it the same as you. I also found this article very interesting but after thinking about it I couldn’t find any real advantage for this config.lua.

      One negative thing that comes to mind is that the proposed technic will require us to have device specific knowledge in our code (we need to know the aspect ratio of the different devices). A good example against doing it this way is the release of a new device (Kindle HD for example) with a new deviceID. If we use the proposed method you’ll have to release an update to all your games to identify the new device and adjust the dimensions for it. We cannot afford this maintenance with only two programmers and 7 published games…

      I think having a constant viewport size and dealing with the different device resolution in code at run time is a safer option (always being agnostic to specific device IDs).

      Or maybe I didn’t understand something…

      • We also develop with a simple config.lua, with width and height set to 320×480 and “letterBox” scaling. We also treat the letterboxing regions as extra canvas for the game.

        If we want to place a button relative the screen borders, we use “display.screenOriginX” and “display.screenOriginY”; e.g.
        button.x = display.screenOriginX + 30
        button.y = display.screenOriginY + 30

        We also use @2x and @4x resources, etc. Everything seems to work out the same as what is described in this blog post.

        So just what is the advantage of this large and brittle config.lua?

        • Gotta agree with you. A simple config.lua as below works the same way and makes life easier when dealing with positioning.:

          width = 320,
          height = 480,
          scale = “letterBox”,
          xAlign = “center”,
          yAlign = “center”,
          imageSuffix =
          {
          [“@2x”] = 1.5,
          [“@4x”] = 3.0,
          },

  2. Haroon Yaseen says:

    George, one thing confusing me but can not be traced for CHANGE IN BEHAVIOR OF PHYSICS ENGINE. As my game runs for some time, all the physics objects and transitions runs not smoothly (gets stuck for some time (ms) ), There is no any memory issue. any idea about it.

  3. I have a simple question. What will I use as a background image for those resolutions? Will I save 3 image files – original, @2x, @4x – which are 360×570, 540×1710 and 1080×1710 respectively?

    • 360×570, 720×1140 and 1440×2280. My art stays with the suffix, so an @2x image is twice the size of its normal version. I only check to see if I need to use the @2x image when I’m 1.5x or larger. That way even though a device might be a little smaller than @2x but closer to 2x than 1x, we use the better art.

      • Rob – one problem with these sizes (and all background image sizes) are how they consume texture memory. Because of the multiples of 2 concept each of these will bump up to the next largest “memory container”.

        For example:

        1440 x 2280 will consume roughly 30 MB which is the same as if you had used a 2048 x 4096 size image.

        If you scale the 1440 x 2280 proportionately to 1293 x 2048 you will only consume 16 MB of memory and the image is still proportionately accurate.

        If you scale the 1440 x 2280 to 1024 x 2048 you will only consume 8 MB of memory but the image will look “squished” in the height or width (depending on your device orientation)

        To keep the ratio of the image looking correct you would create your art assets at the 1440 x 2280 image size then scale down and let Photoshop (or what ever tool you use) to “squish” the image and then the game engine will scale it back for you to the correct proportions because of the scale factor you are setting. In most cases you will probably not see any difference (or very slight) between the 1440 x 2280 and the 1440 x 2280 scaled/squished to 1024 x 2048 and unscaled/squished by the game engine on the device. Try it :)

        I’ve been in the game industry since the 90’s and we used tricks like this all the time to maximize texture memory back when we were doing Nintendo 64, Dreamcast and Playstation 1 games where memory was extra crucial.

        If you don’t want to have the engine scale you up a little then you might want to think about putting your 1440 x 2048 background image in a 2048 x 4096 or 4096 x 4096 sprite/image sheet with other image assets so you are not wasting all of that extra texture memory.

        • So are you saying to use the 1440 x 2280 image size for the 4x assests, and scale down appropriately to 2x/1x? So:

          2x = 720 x 1140
          1x = 360 x 570

          And this should look ok on most modern devices?

          • Rob Miracle says:

            Yes and no. Mathematically that is the right thing to do. A retina iPad will have to scale that image up a little bit, but it could get downsampled a little on the other HD tablets.

            But the No answer comes in texture memory usage. A 1440×2280 image actually ends up using 2048x4096x4 block of memory. That’s a lot! If memory is a concern (and we are talking backgrounds so there should only be one per scene on average) and it is usually a concern on mobile, you might actually want to scale that image down to 1294×2048 to keep it the texture memory down. It will get scaled up to fit, but at the same time being considerably more memory friendly. Likewise you would hit smaller targets on the 2x and 1x to keep the long side at 1024 and 512 respectfully.

          • Sorry Rob, I’m just trying to get what canvas sizes I should use in Photoshop. What are the three image sizes you use personally? Obviously I am trying to get my app to look good and not pixelated on as many devices as possible.

          • I’m all over the place. But if I had a consistency, I would be using 360×570, 720×1140 and 1440×2280. But as I said if memory is a concern and you have lots of images that are killing your texture memory (say a scene that’s using parallax and you have 3-4 background layers moving at different speeds), that might be too much. On the other hand, most of time if you’re doing parallex, there usually isn’t a lot of detail in the backgrounds and scaling up isn’t a visual hit.

            Ideally you would take the largest screen your going to support (say a Retina iPad at 1536×2048 and start there, making it 1536×2730 and size down from there if the texture is important and you’re only using one background layer and can afford to take the memory hit. Either the 1440×220 or 1536×2730 is going to be a 32MB image in memory as opposed to 16MB’s for 1294×2048 that’s going to scale up.

          • My app doesn’t consist of very many images, and none of which will take up the entire screen (it is more of a business app). It is imperative that everything look very sharp and clean. I was just asking what sizes you use for the background images just so I can use the same as the canvas size in photoshop to do my layouts. I guess I will use the iPad 3 resolution as my 4x. So would I just scale down to 50% and 25% for the 2x and 1x sizes respectively? Sorry if I’m a stubborn mule, but this is really my first serious Corona project.

          • Awesome, thanks for all your help. One last question, can I just drop in your config file with the dimensions I’ll be using (1x = 384×512, 2x = 768×1024, 4x = 1536×2048) and everything will work correctly? Or are there adjustments needed to the code?

  4. This confuses me completely, I don’t understand how you can ever have different screen sizes in your config file.

    Isn’t stuff gonna be in different places on each device ?

    Doing it the normal way and using the sticky in the developer forum seems a way better way to do it and use just have extra space on bigger devices to place stuff.

    Dave

    • You could just have everything as a 320×480 and just offer a bigger background but then you’re not able to use the extra real-estate that the 16:9 devices give you and you risk having things cut off on the iPads since they are shorter.

      It does take more thinking about positioning things and it helps avoid the distortion than zoomStretch brings to the table or the cropping that zoomEven brings.

      Barnes and Noble has gotten very picky about apps that don’t use the full screen. Apple encourages iPhone 5 support to not letterBox the extra space (though they have to allow it because of the shear number of legacy apps).

    • Not any easier than you’re doing now.

      Let’s look at this example. Assume you start landscape and you’re using a fixed shape like 320×480 on all devices. Since we start landscape our screen is now 480×320. You place a “Home” button at x = 460, y = 20. When you rotate the device, it’s now 320×480 and that x = 460 is now off screen since you’re only 320px wide. To solve that, you likely will do something like: homeBtn.y = display.contentWidth – 20. When the orientation changes, the button moves to the right spot. This is called anchoring to one side.

      You end up then having to do the same things at the bottom edge. If you’re portrait and you put something at y = 460 and rotate the screen horizontal, that is now off screen. So you do bottomGraphic.y = display.contentHeight – 20.

      At this point you’ve started to position your graphics relative to the edges to keep them on screen and you’re allowing them to move. This is the same idea that my config.lua supports except instead of having to move things because they are landscape or vertical, we let them move to occupy the extra or less space available to the screen space.

      In both scenarios (moving because your rotating or moving because the device shape is different) means things change positions relative to center. Somethings get closer sometimes, other times further away.

      If your objects have to stay a fixed distance away from center, then you use the center points and some relative distance to maintain those critical bits that can’t change due to orientation or shape differences. player.x = display.contentCenterX – 100 for instance will keep the player object 100 px left of center regardless of orientation or shape.

      And as always, if what you have is working for you, no need to change it but when you ask how do I use that extra space on my iPhone 5 and still make it work on the iPad without squeezing/stretching or having something cut off, then give this a try.

  5. That’s quite the read! I do something similar to Charlie where all my essential things happen in a 320×480(or vice versa) area. If your screen is larger you either get to see more of the level or just some non-essential graphics.

  6. In the CoronaBigMeetup the other day, one of the things I talked about was setting up a config.lua also! Our minds are in sync Mr Miracle! I do it a little differently in that I use a method of calculating the actual screen size ratio using display.pixelWidth and pixelHeight, then applying that to a width of 320 (or 360 for an ipad), and then I can determine what the actual height is supposed to be for every device.

    The first part of the bigCoronaMeetup you can see below. All of the presentations are awesome, but in regards to the config file, my presentation is about 50 minutes in.
    http://www.youtube.com/watch?v=23PPMxMftD0

    • I was considering using the method of calculating the ratio like that for this post as it greatly simplifies the code, but the benefits for getting people to understand using string.sub() to help identify devices had value.

      In testing, the calculated ratio works quite well and I really only have to separate the iPad from the rest since I want to use 360 instead of 320 for it.

  7. Rob, this is awesome! Thank you so much for putting it together. I’m getting ready to get Blendamaze released on Nook and Kindle and was wondering how to do some of the techniques you describe above. Thank you!!

  8. Hi Rob, Glad to see the @2x and @4x at 1.5 and 4 respectively. I had settled on this a while ago, due to some screen sizes of android devices. This seemed like the perfect fit for all devices to get the best possible resolution.

    However I still design everything based on 320×480. This keeps all the distances the same for in game physics. Though what I do to fill up the Real Estate is use display.pixelHeight-30 for placement of menu buttons etc and have the background centered and set at 400×600 which covers all device sizes. I find this to be the best way forward for me as it has the benefits of a simple config.lua, yet also fills all the various screens real estate

    For me having the physics the same in all versions is paramount.
    Being able to place the menu buttons etc at the device edges is indeed straightforward to do, so it’s win win!

  9. Hello Rob,
    This is great, but i wonder if it effects the saved image when we use display.save().
    Before, i use this dynamic content scaling in my project with iPhone 3GS base, but unfortunately, display.save() doesn’t save the full screen in iPad. My only way is to separate the 2 versions, which i believe it’s not the best way. I don’t know if corona has improved or fixed it yet. Do you have any idea about this? Thanks.

  10. display.pixelHeight not working on iPhone 5 or xCode sim!

    Can someone confirm? Ik get only 960 pixels if I add print(display.pixelHeight) to the config.lua

    In coronaSim is works fine.

  11. I Have a question. Her is what I use for my config file:

    application =
    {
    content =
    {
    width = 1365,
    height = 2048,
    scale = “letterbox”
    },

    notification =
    {
    iphone =
    {
    types =
    {
    “badge”, “sound”, “alert”
    }
    }
    }
    }

    It is the highest resolution possible (iPad Retina) with the edges cut away, so that the the screen proportions are like on the iPhone 4. Then I create the pictures the large size, so I dont need to have 3 times as many pictures for all of the devices.

    Am I doing something wrong, or why doesn’t anyone do that? Whats the point of having many different images, if you can just create the large ones, and sclae them down with letterbox?

    • Life is all about balance. The reason I do not do this is because of how much memory and CPU power is needed to make this work.

      Your 1365×2048 background is a 2048x2048x4 bytes of texture memory, or 16MB just for the one background. Lets say you have an asset like a heads up display bar that’s going to span most of the 1365 width, for example say 1200×200. That also takes up a 2048x2048x4 block of texture memory or another 16MB. You have a button that for this scale need to be 300×300, that rounds up to 512×512 or 1MB of memory just for a button.

      If you want to run your app on an iPhone 3GS or an iPad 1 with their 256M of memory, you’re going to run out of memory in a real hurry. Those devices also don’t have the swiftest CPU on the planet and to downscale large images to 1/4 their size and have them look good requires lots of processing power and those devices are underpowered. Your app will likely perform poorly on those devices.

      The iPad 2 and iPhone 4/4S are a bit quicker and have more memory, but when you’re eating 16MB textures like candy, even they will be sluggish.

      By having assets scaled more closely to the size you really need does eat up more space in your app bundle making it take up more space on the device and longer to download, but your performance on older devices should be noticeably better.

      • Hi Rob,

        So I have one small question in regards to that. I always work to the rule that textures should be divisible by two so, 128, 256, 512 etc. My question is if I make a texture that is, say 570 pixels wide to accommodate overlap, does that mean Corona treats it as 1024 pixels?

        Great post.

        • Dan, yes you are correct. If either the width or height of your image is greater than the texture size of 128, 256, 512, etc. it will use the next larger size.

          Thus 570 will be use the 1024 memory space. As I mentioned in my earlier post of this thread – try making your image 323 x 512 ( but specify 360 x 570 as the image size in the code when creating the image: local myImage = display.newRect(0, 0, 360, 570) ) and let Corona scale it up for you. I don’t think you will notice any difference in quality between the 323 x 512 image and the 360 x 570 image.

        • If you’re talking about having the backgrounds bigger than 512, while it’s true the texture memory will jump up to the next power of two, this is only your backgrounds. So if you’re on a device where this causes you to have a big texture, it’s generally only one file. Now if all your assets are @4x size and you’re letting Corona scale it down for you, then you will likely have memory problems on the 3Gs and iPad 1. But if you’re providing 1x, 2x and 4x graphics (if needed) then Corona will pick the right one and a 3Gs/iPad 1 can easily handle a 4MB background image. A 64MB background from a 4096x4096x4 texture, will cause issues for the low memory devices.

          Stiven, you probably will be okay, if I’m reading you’re question right.

          • Ok, so if I don’t want to change any resolutions or coordinates in my files, and I have only x4 graphics, what should I do? Should I just scale down all the pictures and put them as @4x, @2x, etc. or is there something else I need to do?

            I just don’t want to change all coordinates, and remake my app for a smaller display.

            Also do I need to change all my pictures to display.newImageRect and specify the size?

    • 800/480 is a 1.66666 ratio screen and works out to 533×320 when scaled there. It’s about half way between the 320×512 and 320×570 screens. It would be easy enough to add another test to see if the pixelHeight / pixelWidth was > 1.6 and less than 1.7 and do a size for those screens.

  12. Hi Rob, I would like to have a different screen layout between an Android smartphone and an Android tablet. For example:
    – Nexus 4 is 4.7″ and 1280 x 768
    – Galaxy Tab 8.9″ is 1280 x 800
    The resolution and aspect ratios are almost the same but just scaling up a smartphone screen layout to a larger tablet size can be ugly. Android uses the concept of small/normal/large/xlarge or ldpi/mdpi/hdpi/xhdpi to tell the difference between physical device sizes. Any ideas on how to do this in Corona?

  13. @Rob Miracle Hi Rob, i replaced your config file and loaded up my blank new corona project and on all the If statements theres a yellow warning sign that says – “Class Mismatch. Expected class of type: string got: varies”

    Any idea why?

  14. Hi,

    I found this article really helpful. I recently created an app for iOS and then quickly wanted to get it out for Android as well. In doing so I used the concepts here and incorporated a tip from Ninja Pig about setting the ‘scale’ attr to ‘ZoomStretch’ for Android devices which worked perfectly in my case. Here’s a slightly streamlined version of the code from this article with the scale setting added:

    ———————————————————————————–
    — determine the correct width & height based on the device
    local device = { model_name = system.getInfo( “model” ) }
    device.scale_mode = “letterbox”

    if ( string.sub( device.model_name, 1, 4 ) == “iPad” ) then
    — iPad
    device.width = 360
    device.height = 480

    elseif ( string.sub( device.model_name, 1, 2 ) == “iP” and display.pixelHeight > 960 ) then
    — iPhone5
    device.width = 320
    device.height = 568

    elseif ( string.sub( device.model_name, 1, 2 ) == “iP” ) then
    — iPhone4 & older
    device.width = 320
    device.height = 480

    elseif ( display.pixelHeight / display.pixelWidth > 1.72 ) then
    — Android 16:9 ratio devices
    device.width = 320
    device.height = 570
    device.scale_mode = “zoomStretch”

    else
    — other Android devices
    device.width = 320
    device.height = 512
    device.scale_mode = “zoomStretch”

    end

    — define the application details

    application = {
    content = {
    width = device.width,
    height = device.height,
    scale = device.scale_mode,
    xAlign = “center”,
    yAlign = “center”,
    fps = 30,
    –[[
    image_suffix = {
    [ “@2x” ] = 1.5,
    [ “@4x” ] = 3.0,
    }
    –]]
    },
    }

  15. Rob,
    I am using your config file. Everything works well, except the positioning of the inneractive ads.
    On iPad the ads end up in the middle of the screen.
    How to position them such that they are at the bottom of the screen in every device?
    I have this for the ads:
    if string.sub(model, 1, 4) == “iPad” then
    ads.init( “inneractive”, “myappID_iPad” )
    ads.show( “banner”, { x=0, y=display.contentHeight – 66, interval=40} )
    else
    ads.init( “inneractive”, “myappID_iPhone” )
    ads.show( “banner”, { x=0, y=display.contentHeight – 53, interval=40} )
    end

  16. Hi Rob
    Thanks for this great tutorial!!!
    Could you put a little example with a main.lua file and some assets to understand how all these stuffs works together?
    It would be very helpfull :))
    Olivier

  17. Rob
    Am I right if
    – all my backgrounds images are at the maximum size: 2280 * 1440 pixels
    – All my assets width and height are based on this background size

    Corona will manage everything behind the scene, and for example, will reduce my backgrounds and my assets if it’s necessary?

    In other words, am I right if I have only the biggest version of all my assets and background? No needs to make a version of all these stuffs for each device case?

    Thank you for your lights :)
    Olivier

    • A 2280 x 1440 image ends up being a 4096x4096x4 block of texture memory (64MB) per image that size, even if you’re running on an iPad 2 or Phone and we are scaling it down. If you resized them to 1292×2048, they would still have to scale up on Retina iPads, but would be a 2048x2048x4 block of memory (16MB) and be much kinder to your system. But even then, when you’re working with older but very popular devices like the iPad 2, your tasking the CPU with downsizing all of that, with half the memory of a Modern iPad. This is the reason why the concept of @2x and @4x images are around. An iPad 1 or a 3Gs only have 256M of memory and very pokey CPUs. While it increases your download size, it’s better on the performance to provide multiple resolution images.

  18. Perfect for my game, as i really didn’t want letterboxing, and i can be flexible about ratios.

    I’m notice some failing in the simulator, on nexus one and galaxy tab, I’m still getting letterbox, is this just a sim thing or devices too? I don’t have either device to test on.

  19. I am using three images in my project
    a.png
    a@2x.png
    a@4x.png

    and make setting in config.lua file

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

    It is not working for me. It loading only single a.png for iphone and ipad both , it is not load dynamic image as per device.

    Please help anyone
    Thanks.

  20. For some reason, this works cool on the mac corona simulator but not on the device. :( I’ve tried with iPhone5 and iPad3 and it shows letterboxed, but in simulator appears ok.

  21. Is there any reason why we should not keep it simple?

    if ( string.sub( system.getInfo(“model”), 1, 4 ) == “iPad” ) then
    application =
    {
    content =
    {
    width = 360,
    height = 480,
    scale = “letterBox”,
    xAlign = “center”,
    yAlign = “center”,
    imageSuffix =
    {
    [“@2x”] = 1.5,
    [“@4x”] = 3.0,
    },
    },
    }
    else — all other devices

    local h = math.round(320 * (display.pixelHeight / display.pixelWidth));

    application =
    {
    content =
    {
    width = 320,
    height = h,
    scale = “letterBox”,
    xAlign = “center”,
    yAlign = “center”,
    imageSuffix =
    {
    [“@2x”] = 1.5,
    [“@4x”] = 3.0,
    },
    },
    }
    end

  22. Your Comment Here…Hi Rob,
    Thanks again for this tutorial

    You said :”Please note that the config.lua file is always configured as if you’re doing a “portrait” app. If you’re designing an app in “landscape” mode, you should still specify width and height in the portrait orientation — Corona will manage the translation for you.”

    My app is in landscape mode, so my build.settings looks like this :

    orientation = {
    default = “landscapeRight”,
    supported = { “landscapeRight”, }
    },

    And my config.lua is like yours

    I have my 3 background images,
    bg.png (360×570)
    bg@2x.png (720×1140)
    bg@4x.png (1440×2280)

    For me it doesn’t work, background stays on a portrait mode
    Did I miss something?
    Thanks for your help
    Sincerely
    Olivier

    • What that means is that if you are building a portrait app you would set the width to 320 and the height to 480. Logic would say if you’re building a landscape app you would set the width to 480 and the height to 320, but that’s not what’s being looked for here. Even if you intend on landscape, you still set the width to 320 and the height to 480.

      Now your assets like your backgrounds would be landscape.

      For my landscape only apps, this is what I put in my build.settings:

      orientation =
      {
      default = “landscapeRight”,
      supported =
      {
      “landscapeRight”, “landscapeLeft”
      },
      },

      Also in the iphone -> plist area I also include this:

      UIInterfaceOrientation = “UIInterfaceOrientationLandscapeLeft”,
      UISupportedInterfaceOrientations =
      {
      “UIInterfaceOrientationLandscapeLeft”,
      “UIInterfaceOrientationLandscapeRight”
      },

      but that only affects iOS devices. There is not an Android equivalent that I know of.

  23. Why does this config.lua file work perfect for all devices in the simulator and when I transfer the app to an iphone 5 it has again the black borders? Any idea or is the scale mode zoomStretch not working on a device?
    Thanks for any help
    Michael

    — config.lua
    application =
    {
    content =
    {
    width = 480,
    height = 720,
    scale = “zoomStretch”,
    fps = 30,
    antialias = false,
    xAlign = “center”,
    yAlign = “center”,
    },
    }

    — build.settings
    settings =
    {
    orientation =
    {
    default =”landscapeRight”,

    supported =
    {
    “landscapeLeft”,”landscapeRight”,
    },
    },

    iphone =
    {
    components = {},
    plist =
    {
    UIApplicationExitsOnSuspend = false,
    UIStatusBarHidden = true,
    CFBundleDisplayName = “ABCDEFG”,
    FacebookAppID = “1111111111111111”,
    CFBundleURLTypes = {
    {
    CFBundleURLSchemes = { “fb1111111111111111″, }
    }
    }
    },
    },
    }

  24. Rob,

    I don’t quite follow how one is supposed to use the setup. For the background image the options seem to be:

    (a) display.newImageRect( “background.png”, 360, 570 ), using dimensions of x1 actual image you have, but:
    – no stretching of the image but
    – when running this on many devices (e.g. iPhone 4) not all of the image will be displayed, with some being cut off

    (b) display.newImageRect( “background.png”, display.contentWidth, display.contentHeight)
    – good match re all image is displayed but,
    – needs to stretch the image, e.g. for iPhone5 will stretch the image horizontally

    Question 1 – What is the approach you intended, and what is the development approach you would need to follow? For example for (a) do you need to work out the maximun area that might be cropped and then in Photoshop draw a reminder rectangle so you keep in mind what might be cutoff?

    Question 2 – What would be your thoughts in terms of a horizontal scrolling game where currently the ground level (which goes up and down) is part of the background. If I wanted to move from a fixed config.lua width & height (but letterbox’ing at ends) to a “use all horizontal screen available” approach, then will I need to disassociate the ground level graph from the background? That is, add the ground dynamically to the background after background is rendered, therefore ensuring left hand edge of ground (with starting line) lines up exactly with the left hand side for whatever device the user is on?

  25. i used your confing.lua, then written this in the main.lua, not working

    display.setStatusBar( display.HiddenStatusBar )

    background = display.newImageRect( “background.png”, 360 , 570 )
    –background = display.newImageRect( “background.png”, display.contentWidth , display.contentHeight )

    –background.x = display.contentWidth / 2
    –background.y = display.contentHeight / 2

    print ( ” done ” )

  26. background is not centered. if i place it with display.Content * / 2, it is better, but i still don’t correctly see the angles of the background.
    see: http://db.tt/N8LWb3ts

    thanks for reply.

    ps: when you publish an app, you can specify on Google Play or Apple Store, a list of not-supported resolutions or devices? Can I just use the “hd” resolution (“@x4″ files only) ignoring old devices?

  27. Sorry confused. I don’t know what a .7z file is. If you want to post a screen shot please do it as a .jpg or .png file.

    I always still manually center by backgrounds:

    bg.x = display.contentCenterX
    bg.y = display.contentCenterY

    Google Play lets you limit devices (though I don’t know the specifics). Apple is much harder to restrict devices.

  28. Rob Miracle says:

    This is what I changed your main.lua too. I got a full screen blue box with some text on it (the @2x image) near the top and just a little left of center.

    display.setStatusBar( display.HiddenStatusBar )

    background = display.newImageRect( “background.png”, 360 , 570 )
    display.contentHeight )

    background.x = display.contentWidth / 2
    background.y = display.contentHeight / 2

    print ( ” done ” )

    • Hi Rob,

      Here we are developing 12 games and planning to release them in single file. Now the problem is few games are in portrait mode and others are in landscape. But there is only one config.lua, were we have specified it as landscape, because of that portrait games are not working . So my question is that how to run both the modes using single config file. Give us some suggestions.

      • The config.lua is **ALWAYS** done in portrait mode. This has no impact on if you’re app will be portrait or landscape. You manage portrait/landscape mode in the build.settings file.

  29. Hi guys,

    I’ve been using this for a while now, but in my new app I need a lot of masks for images, and I have problems with that because the masks are a fixed size, but then depending on the device my images could be “wider”.
    So, how do you handle this?
    Also when using masks the loading par gets real slow, since all the masks are now @4x size, do you have this problem as well?

    Thanks

  30. experiments with coords:

    a)
    coords referring from top-left-angle work on “droid” but get shifted on the other devices:
    sprite.x = 82 — 82!
    sprite.y = 390 — 390!

    b)
    as explained in the article, coords referring from center work when you change device:
    sprite.x = display.contentCenterX – 78 — 78?
    sprite.y = display.contentCenterY + 105 — 105?

    c)
    if you prefer to give to the coords like (a) but getting the result like (b), I suggest:
    sprite.x = ( display.contentCenterX – 320 / 2 ) + 82 — 82!
    sprite.y = ( display.contentCenterY – 570 / 2 ) + 390 — 390!

    the math above can be written as function: sprite.x = setX(82) etc.

  31. @Juan Cruz Martinez, your mask files do not need to be @2x and @4x versions. The 1x size scales up just fine. I’m not sure what your masking, but if the size of the hole (the part that shows) is a fixed size, then it should work as expected. Masks don’t have to cover the whole screen. The white area covers the area you want to show and then as long as you have at least 4 px of black border around it (and the total width/height is divisible by 4) it should just work.

  32. Hello im having problems…. I was trying to do only the android part because that’s all I needed. When I put in the codes and run the app it dosent work it zooms in instead of fitting the devices screen size.

    please help, thank you

  33. Hi Rob
    You use these “IF” statements :

    _____________________________________________________________________________

    if ( string.sub( system.getInfo(“model”), 1, 4 ) == “iPad” ) then

    elseif ( string.sub( system.getInfo(“model”), 1, 2 ) == “iP” and display.pixelHeight > 960 ) then

    elseif ( string.sub( system.getInfo(“model”), 1, 2 ) == “iP” ) then

    _____________________________________________________________________________

    Corona Simulator doesn’t make any difference
    – between iPhone 5, 5c and 5s
    – between several iPad Retina models (Mini, Air etc.)
    Does Apple make a difference?

    with the new iPad Air Retina, iPad 4 Retina, iPhone 5C and iPhone 5s,
    and all the new devices with new 64-bit A7 processor,
    What are the returned values for the statements above?

    Thank you for your answer!
    Best
    Olivier

    • The Apple 5, 5s and 5c share the same screen resolution (and more importantly aspect ratio). The iPhone 3Gs, 4 and 4s, share the same aspect ratio (though the 3Gs is a lower resolution). All iPads share the same aspect ratio (though there are two different resolutions).

      This config.lua (and you probably should look for the updated version “Modernizing the ultimate config.lua” will build the proper aspect ratio for all Apple devices. Resolution is handled by Corona’s Dynamic scaling engine (the @2x and @4x image sizes and prefix system).

      As far as config.lua there isn’t anything else you need to know to separate an iPhone 5s from a 5. Now there is another API call as part of system.getInfo(“architectureInfo”) that will return a string like iPhone5,3 which can be used to determine the specific model.

      Rob

  34. Hi

    I have read this but still a little bit not clear
    I am using the sony ericsson with the (480 x 854 pixels, 4.2 inches (~233 ppi pixel density))
    how can i put it in the config file?

    thanks in advance
    Keat

    • Rob Miracle says:

      Hi Seng. If your goal is to only support that one device you don’t need this config file. Just set the width and height to 480 and 854. But the idea behind this config is to support all devices, not just your device. If you use the 320×480 version, then your Sony Ericson will use your @2x assets and scale them down accordingly. If you use the 800×1200 variant it will use your 1x assets and scale them down.

      Rob

  35. Hi Rob,

    I know this is an old “tutorial” but NOOB question here.

    Let’s say i have a Photoshop mockup (Ipad Retina Size 1536X2048)
    In this File i have 5 layers representing 5 buttons.

    Each of this button size is 200X100 (in my photoshop file)
    Now let’s say that i am using “ultimate config.lua”

    How should i name my buttons and what will be them size?

    Exemple for button01.png :

    button01.png ( 50X25)
    button01@2x.png (100X50)
    button01@4x.png (200X100) —> my photoshop size

    Can you tell me if this is accurate?
    If not can you tell me the way to do it?

    Also i am not really interesting by having 3 different png but only 2…what will be the ones i have to keep in this situation?

    I am really sorry, i know this is a lot of question but i had check all the comment and i didn’t find any answers.
    Thank you for your time

    • Yes, that is exactly what you want to do.

      If you want to drop to only having two image files and you don’t plan on using widgets (some of our widgets don’t scale and are designed for 320×480 size screens), then you can change your width and height in the config.lua to not be based on 320 x 570 and 360 x 480 sizes and instead go to the 2x sizes as the default::

      640×1140 and 720×960. At that point, you can loose the @4x and just have normal and @2x where in your example normal would be 100×50 and @2x would be 200×100

      Rob

      • Hi Rob,

        I tried your way but once i changed the width and height the button are at good size but my “scrollview” becoming really small on Iphone 5…

        With the “ultimate config.lua” the buttons are way too big…and even if i name them good.

        I’m calling my images this way :

        local mylistimg = display.newImageRect( “menu01.png”, 200, 100 )
        width and height are the exact size of my layers on photoshop

        But if i do divide the width and height per 2 in my code the result is good.

        If i keep naming them :
        button01.png (100X50)
        button01@2x.png (200X100)

        and divide my images width and height per 2 in the code..would it be ok?

        Thank you

        • You will probably need to double the size of your scrollView. Be aware that the scrollBars are one of the things that doesn’t scale up.

          You don’t want to load images that are twice as large and then scale them down because they end up using four times the texture memory and the CPU/GPU has to do more number crunching which will impact any older devices that you would be running on.

          • Just to make sure.
            I only need to change this in the config.lua :

            elseif display.pixelHeight / display.pixelWidth > 1.72 then
            application =
            {
            content =
            {
            width = 320,
            height = 570,
            scale = “letterBox”,
            xAlign = “center”,
            yAlign = “center”,
            imageSuffix =
            {
            [“@2x”] = 1.5,
            [“@4x”] = 3.0,
            },
            },
            }

            By ->

            elseif display.pixelHeight / display.pixelWidth > 1.72 then
            application =
            {
            content =
            {
            width = 640,
            height = 1140,
            scale = “letterBox”,
            xAlign = “center”,
            yAlign = “center”,
            imageSuffix =
            {
            [“@2x”] = 1.5,
            [“@4x”] = 3.0,
            },
            },
            }

            And also :

            if string.sub(system.getInfo(“model”),1,4) == “iPad” then
            application =
            {
            content =
            {
            width = 360,
            height = 480,
            scale = “letterBox”,
            xAlign = “center”,
            yAlign = “center”,
            imageSuffix =
            {
            [“@2x”] = 1.5,
            [“@4x”] = 3.0,
            },
            },
            notification =
            {
            iphone = {
            types = {
            “badge”, “sound”, “alert”
            }
            }
            }
            }

            By ->

            if string.sub(system.getInfo(“model”),1,4) == “iPad” then
            application =
            {
            content =
            {
            width = 640,
            height = 960,
            scale = “letterBox”,
            xAlign = “center”,
            yAlign = “center”,
            imageSuffix =
            {
            [“@2x”] = 1.5,
            [“@4x”] = 3.0,
            },
            },
            notification =
            {
            iphone = {
            types = {
            “badge”, “sound”, “alert”
            }
            }
            }
            }

            Thank you

  36. Code doesn’t display well in blog post comments. This isn’t the best place to provide support for these ideas. Please post this in the forum and ask for help there.

    Rob

  37. I mean i just need to change :

    width = 320,
    height = 570

    By->

    width = 640,
    height = 1140,

    And :

    width = 360,
    height = 480,

    By=>

    width = 720,
    height = 960,

    in the config.lua?
    Thank you Rob

    • I’ll probably be working on an update for the blogs soon. I’ve already started working out new numbers to build with for people who want the same thing on all the devices. But if you want to have the devices have extra real estate, I’m probably going to have to wait until I get my hands on the devices to see how to make that work.

      We will update the community when we have something cool to show you.

      Rob

  38. hey Rob
    thanks for this code
    but i have few question is this config better than using dynamic scaling
    and if i want to use this code do i need to provider assets for each size i provided?
    of using same larger size assets and depend on scaling?

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>