How do you position different sized objects with varying screen dimensions and keep everything positioned the same?

Hi all :slight_smile:

This is my first post and it’s quite a complex issue.
I’ve been learning Corona for about 3 weeks and jumped straight in and started coding my first ever app.

I have 4 “touch event” buttons on the screen and 6 other static graphics, I’ve been placing them relative to the screen centre using these variables,
scH=display.contentHeight*0.5 and scW=display.contentWidth*0.5
For example: button1.x=scW-170; button1.y=scH+105, everything looked good and the app ran perfect with a 360X480 screen res.

I got level 1 working exactly how I wanted it and was about to start implementing Storyboard for the other levels when I realised I had better make sure my app would work on different devices with different screen resolutions before things got too complex.

I made all my graphics in the 3 usual sizes, normal, @2x & @4x and used Rob Miracle’s ultimate config lua.

This is where things get messed up. :wacko:
When I use the simulator with the new config.lua everything is all over the place.

How do I know which size graphics the simulator is picking from the 3 provided when there are so many screen resolutions?
Is there a formula to place my buttons correctly, screen size/button size/space between buttons?
Or would I be better off creating my app for one device at a time?

I’m sure the professional coders here have to deal with this in their own apps all the time so I’m hoping you can give me some of your wisdom or tips on how you tackle this issue.

I can’t find the answers anywhere, please help! :frowning:

Hi QuizMaster,

Welcome to Corona!

For the config.lua file, the ultimate config.lua was updated by Rob a few months ago. Please see this for the updated config.lua http://coronalabs.com/blog/2013/09/10/modernizing-the-config-lua/

After you read that blog post, you will see that the @4x size has been removed and the standard 360x480 screen size has been increased to make things easier.

As for placement of buttons, when using pixel numbers like you have been it can get a little bit tricky sometimes. I prefer to work with percentages. I use 

display.contentWidth

 and 

display.contentHeight

 as my 100% and place everything from there. So if I wanted to place an image at the center of the screen, I would use

local img = display.newImage("ImageName.jpg") img.x = display.contentWidth \* 0.5 img.y = display.contentHeight \* 0.5

At the same time, If I wanted to place the image centered horizontally but only a quarter from the top, I would use 

local img = display.newImage("ImageName.jpg") img.x = display.contentWidth \* 0.5 img.y = display.contentHeight \* 0.25

In my opinion, percentages are much easier to work with in terms of screen space. And this is not the only time percentages are used. They are also used when setting a fill color (the usual rgb values of (255, 255, 255) are now (1, 1, 1) where 1 is 255 or 100%) as well as anchor points (also a new system in graphics 2.0).

Another thing to point out is that by default, all anchor points are at the center of the image (0.5, 0.5). To put it simply, an anchor point is the point by which an object is placed. When you set the “X” and “Y” values of an object, it sets the anchor point to that “X” and “Y”. You can find more about anchor points here http://coronalabs.com/blog/2013/10/15/tutorial-anchor-points-in-graphics-2-0/ and here http://www.develephant.net/3-things-you-need-to-know-about-corona-sdk-graphics-2-0/

Hope this helps!

Eric

Hi Eric

Thanks very much for your help and taking the time to write such a detailed reply.

I will rethink my positioning and use percentages like you suggest, it makes sense! :smiley:

I was also mystified about setting the RGB values, with values between 0 and 1, now it makes sense thanks to you.

I’ve read Rob’s update to the cinfig.lua as you suggested, this raised a question, he stated:

“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.”

Would you recommend I work with a content area of 800X1200 from now on? Do you?

Is the config.lua code really this small?

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,
      },
   },
}

Thanks again Eric :smiley:

Hi QuizMaster,
 
Glad I could help!
 
As for the new config.lua, everyone has their personal preference. I personally use the one you just posted. And yes, my config.lua is really that small.
 
For background images or other images that cover the entire screen, you also have to keep in mind that not all devices have the same aspect ratio. Rob Miracle posted a comment on his config.lua blog post that explains this. Here it is:
 
“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 for a background image or image that covers the whole screen, I use 900x1425 as the base and double it to 1800x2850 for the @2x.

Hope this helps! Let me know if you have more questions or if this confused you.

Eric

Eric you’re a star, you’ve answered my question exactly, thanks.

Hi QuizMaster,

Welcome to Corona!

For the config.lua file, the ultimate config.lua was updated by Rob a few months ago. Please see this for the updated config.lua http://coronalabs.com/blog/2013/09/10/modernizing-the-config-lua/

After you read that blog post, you will see that the @4x size has been removed and the standard 360x480 screen size has been increased to make things easier.

As for placement of buttons, when using pixel numbers like you have been it can get a little bit tricky sometimes. I prefer to work with percentages. I use 

display.contentWidth

 and 

display.contentHeight

 as my 100% and place everything from there. So if I wanted to place an image at the center of the screen, I would use

local img = display.newImage("ImageName.jpg") img.x = display.contentWidth \* 0.5 img.y = display.contentHeight \* 0.5

At the same time, If I wanted to place the image centered horizontally but only a quarter from the top, I would use 

local img = display.newImage("ImageName.jpg") img.x = display.contentWidth \* 0.5 img.y = display.contentHeight \* 0.25

In my opinion, percentages are much easier to work with in terms of screen space. And this is not the only time percentages are used. They are also used when setting a fill color (the usual rgb values of (255, 255, 255) are now (1, 1, 1) where 1 is 255 or 100%) as well as anchor points (also a new system in graphics 2.0).

Another thing to point out is that by default, all anchor points are at the center of the image (0.5, 0.5). To put it simply, an anchor point is the point by which an object is placed. When you set the “X” and “Y” values of an object, it sets the anchor point to that “X” and “Y”. You can find more about anchor points here http://coronalabs.com/blog/2013/10/15/tutorial-anchor-points-in-graphics-2-0/ and here http://www.develephant.net/3-things-you-need-to-know-about-corona-sdk-graphics-2-0/

Hope this helps!

Eric

Hi Eric

Thanks very much for your help and taking the time to write such a detailed reply.

I will rethink my positioning and use percentages like you suggest, it makes sense! :smiley:

I was also mystified about setting the RGB values, with values between 0 and 1, now it makes sense thanks to you.

I’ve read Rob’s update to the cinfig.lua as you suggested, this raised a question, he stated:

“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.”

Would you recommend I work with a content area of 800X1200 from now on? Do you?

Is the config.lua code really this small?

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,
      },
   },
}

Thanks again Eric :smiley:

Hi QuizMaster,
 
Glad I could help!
 
As for the new config.lua, everyone has their personal preference. I personally use the one you just posted. And yes, my config.lua is really that small.
 
For background images or other images that cover the entire screen, you also have to keep in mind that not all devices have the same aspect ratio. Rob Miracle posted a comment on his config.lua blog post that explains this. Here it is:
 
“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 for a background image or image that covers the whole screen, I use 900x1425 as the base and double it to 1800x2850 for the @2x.

Hope this helps! Let me know if you have more questions or if this confused you.

Eric

Eric you’re a star, you’ve answered my question exactly, thanks.

I know this is an old post but I just want to say thanks anyway.  As another newbie, the positioning across multiple devices was confusing.  I knew that it should be simple but couldnt find a post that clearly told me what I needed.  It makes perfect sense to use percentages once you said it but all articles / examples speak in pixels so think I had tunnel vision!

One quick question…  say you had a footer type image in you app that had the score, etc.  How would you ensure that it ‘anchored’ on say the iphone 4 vs the taller iphone 5?

I just tried the below thinking that it would work but when I use the iphone 5 simulator it had a gap at the bottom…

maybe I dont get it after all haha

local footer1 = display.newRect( 0, 0, display.contentWidth, 50 ) footer1.anchorX = 0 footer1.anchorY = 0 footer1.y = display.contentHeight - 50

however, if I did the following below.  The square does display in the center vertically on all the iphone simulators, even the taller 5…

local rect1 = display.newRect( 0, 0, 50, 50 ) rect1:setFillColor( 1, 0, 0 ) rect1.x = display.contentWidth \* 0.5 rect1.y = display.contentHeight \* 0.5

I’m sure I have done something wrong somewhere!

Hi David

From what I understand you have it corect in the second code snippet.

The problem with the first bit of code is that you used a whole number -50 which translates as 50 pixels up from the center of the screen.

If you have different screen heights then 50 pixels can either be a small move up or it could be a big move up depending on how many pixels there are from the center of the screen to the top, it could be 400 pixels (12.5% more up) or it could be 600 pixels ( only 8% up) depending on the phone.

It makes more sense to use what you know is the same on every phone, contentHeight. Then half of the screen height is found by multiplying content height by 0.5, no matter the phone it will always be half way down the screen. Or multiply by 0.1 to be 10% down from the top of the screen or *0.9 to be 10% from the bottom of the screen.

Be careful not to fall into the trap of positioning an object…

local rect1 = display.newRect( 0, 0, 50, 50 )
rect1:setFillColor( 1, 0, 0 )
rect1.x = display.contentWidth * 0.5
rect1.y = display.contentHeight * 0.5

…and then moving it down the screen by adding a whole number

rect1.y = rect1.y +50

You should move objects using percentages only, forget whole numbers completely when using screen coords.

If you want to move an object 10% further down the screen then simply multiply it by an extra 0.1

rect1.y = display.contentHeight * 0.6

If you want to be even more precise then you can use 100th’s, I do all the time in my app, I even use 1000th’s

rect1.y = display.contentHeight * 0.642

Save typing and declare these at the top of your code:

local _H=display.contentHeight
local _W=display.contentWidth

then it’s…

rect1.x = _W * 0.5

rect1.y = _H * 0.642

Here’s a snippet from my app…

local okButton = display.newRect( _W*0.778, _H*0.884, 160, 82 )
        okButton:setFillColor( 0.9 )
        okButton.alpha=0.1

        okButton.isVisible = false

        okButton:addEventListener(“touch”, hideKeyboard)

        displayGroup:insert(okButton)

On a different but strangely similar topic…

I would like to point out that I’ve encountered a problem with @2x images on some phones. If you have large images on your screen in normal size then any gaps/spacing  they have between them gets swallowed up by the @2x versions and images can even overlap on some phones. that use the larger @2x graphics but have smaller screen sizes.

Does anyone have any suggestions on how I can fix this…

…do I make my @2x images slightly smaller perhaps?

It would be a pain in the butt because I’ve made over 800 images in both sizes and it would take me hours of mindnumbing resizing. Ouch!

thanks for your reply quiz master.  Just wondering how you would get a rectangle to ‘anchor’ to the bottom of the screen?

Are you using the special config eric suggested?

I have not yet seen that issue with the @2x images yet… what devices are you seeing that on? the simulator or actual devices?

cheers

Hi David

When you say anchor I’m guessing you will have a moving background and want the rectangle to stay in the same place?

That’s easy. You need to create display groups. Put all the moving background images together in a group…

local backgroundGroup = display.newGroup()

   for i = 1, 7 do
        backdisplay[i] = display.newImageRect( “images/background”…i…".png", 1425, 900 )
        backdisplay[i].x = _W*0.5; backdisplay[i].y = _H*0.5
        backgroundGroup:insert(backdisplay[i])
   
   end

then put your buttons, score, lives etc. into another group…

local buttonGroup = display.newGroup()

local okButton = display.newRect( _W*0.778, _H*0.884, 160, 82 )
        okButton:setFillColor( 0.9 )
        okButton.alpha=0.1

        buttonGroup:insert(okButton)

local scoresButton = display.newRect( _W*0.828, _H*0.884, 180, 130 )
        scoresButton:setFillColor( 0.9 )
        scoresButton.alpha=0.01
        scoresButton:addEventListener(“touch”, showHighscores)
        buttonGroup:insert(scoresButton)

Then manipulate the group you want to move like the background…

local myTransition = transition.moveTo( backgroundGroup, { x=0, y=-1000, time=2500 } )

The buttons will stay in place while the background scrolls 1000 pixels up in two and a half seconds.

You can move whole groups of objects and you can still move individual objects within those groups just as easily.

Remember that when placing objects on the screen it matters what order you place them in the group.

Placing an object in a group first puts that object to the very back, the next object put in that group is displayed on top of the previous object and so on. If you have an object that isn’t showing up it’s probably because it’s hiding behind another object.

I’m seeing the @2x problem on the simulator mainly with iphone’s except the iphone 5 and on a few other tablets.

I only have an android phone so I can’t test the problem on real devices.

I know this is an old post but I just want to say thanks anyway.  As another newbie, the positioning across multiple devices was confusing.  I knew that it should be simple but couldnt find a post that clearly told me what I needed.  It makes perfect sense to use percentages once you said it but all articles / examples speak in pixels so think I had tunnel vision!

One quick question…  say you had a footer type image in you app that had the score, etc.  How would you ensure that it ‘anchored’ on say the iphone 4 vs the taller iphone 5?

I just tried the below thinking that it would work but when I use the iphone 5 simulator it had a gap at the bottom…

maybe I dont get it after all haha

local footer1 = display.newRect( 0, 0, display.contentWidth, 50 ) footer1.anchorX = 0 footer1.anchorY = 0 footer1.y = display.contentHeight - 50

however, if I did the following below.  The square does display in the center vertically on all the iphone simulators, even the taller 5…

local rect1 = display.newRect( 0, 0, 50, 50 ) rect1:setFillColor( 1, 0, 0 ) rect1.x = display.contentWidth \* 0.5 rect1.y = display.contentHeight \* 0.5

I’m sure I have done something wrong somewhere!

Hi David

From what I understand you have it corect in the second code snippet.

The problem with the first bit of code is that you used a whole number -50 which translates as 50 pixels up from the center of the screen.

If you have different screen heights then 50 pixels can either be a small move up or it could be a big move up depending on how many pixels there are from the center of the screen to the top, it could be 400 pixels (12.5% more up) or it could be 600 pixels ( only 8% up) depending on the phone.

It makes more sense to use what you know is the same on every phone, contentHeight. Then half of the screen height is found by multiplying content height by 0.5, no matter the phone it will always be half way down the screen. Or multiply by 0.1 to be 10% down from the top of the screen or *0.9 to be 10% from the bottom of the screen.

Be careful not to fall into the trap of positioning an object…

local rect1 = display.newRect( 0, 0, 50, 50 )
rect1:setFillColor( 1, 0, 0 )
rect1.x = display.contentWidth * 0.5
rect1.y = display.contentHeight * 0.5

…and then moving it down the screen by adding a whole number

rect1.y = rect1.y +50

You should move objects using percentages only, forget whole numbers completely when using screen coords.

If you want to move an object 10% further down the screen then simply multiply it by an extra 0.1

rect1.y = display.contentHeight * 0.6

If you want to be even more precise then you can use 100th’s, I do all the time in my app, I even use 1000th’s

rect1.y = display.contentHeight * 0.642

Save typing and declare these at the top of your code:

local _H=display.contentHeight
local _W=display.contentWidth

then it’s…

rect1.x = _W * 0.5

rect1.y = _H * 0.642

Here’s a snippet from my app…

local okButton = display.newRect( _W*0.778, _H*0.884, 160, 82 )
        okButton:setFillColor( 0.9 )
        okButton.alpha=0.1

        okButton.isVisible = false

        okButton:addEventListener(“touch”, hideKeyboard)

        displayGroup:insert(okButton)

On a different but strangely similar topic…

I would like to point out that I’ve encountered a problem with @2x images on some phones. If you have large images on your screen in normal size then any gaps/spacing  they have between them gets swallowed up by the @2x versions and images can even overlap on some phones. that use the larger @2x graphics but have smaller screen sizes.

Does anyone have any suggestions on how I can fix this…

…do I make my @2x images slightly smaller perhaps?

It would be a pain in the butt because I’ve made over 800 images in both sizes and it would take me hours of mindnumbing resizing. Ouch!

thanks for your reply quiz master.  Just wondering how you would get a rectangle to ‘anchor’ to the bottom of the screen?

Are you using the special config eric suggested?

I have not yet seen that issue with the @2x images yet… what devices are you seeing that on? the simulator or actual devices?

cheers

Hi David

When you say anchor I’m guessing you will have a moving background and want the rectangle to stay in the same place?

That’s easy. You need to create display groups. Put all the moving background images together in a group…

local backgroundGroup = display.newGroup()

   for i = 1, 7 do
        backdisplay[i] = display.newImageRect( “images/background”…i…".png", 1425, 900 )
        backdisplay[i].x = _W*0.5; backdisplay[i].y = _H*0.5
        backgroundGroup:insert(backdisplay[i])
   
   end

then put your buttons, score, lives etc. into another group…

local buttonGroup = display.newGroup()

local okButton = display.newRect( _W*0.778, _H*0.884, 160, 82 )
        okButton:setFillColor( 0.9 )
        okButton.alpha=0.1

        buttonGroup:insert(okButton)

local scoresButton = display.newRect( _W*0.828, _H*0.884, 180, 130 )
        scoresButton:setFillColor( 0.9 )
        scoresButton.alpha=0.01
        scoresButton:addEventListener(“touch”, showHighscores)
        buttonGroup:insert(scoresButton)

Then manipulate the group you want to move like the background…

local myTransition = transition.moveTo( backgroundGroup, { x=0, y=-1000, time=2500 } )

The buttons will stay in place while the background scrolls 1000 pixels up in two and a half seconds.

You can move whole groups of objects and you can still move individual objects within those groups just as easily.

Remember that when placing objects on the screen it matters what order you place them in the group.

Placing an object in a group first puts that object to the very back, the next object put in that group is displayed on top of the previous object and so on. If you have an object that isn’t showing up it’s probably because it’s hiding behind another object.

I’m seeing the @2x problem on the simulator mainly with iphone’s except the iphone 5 and on a few other tablets.

I only have an android phone so I can’t test the problem on real devices.