Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Why the fuss with config.lua and variable aspect ratios? (Alternative code inside)
Started by rakoonic2 Sep 12 2013 12:20 PM

* * * * - 1 votes
30 replies to this topic
[TOPIC CONTROLS]
Page 1 of 2 1 2
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

This is the latest article on config.lua:

 

http://coronalabs.com/blog/2013/09/10/modernizing-the-config-lua/

 

I remember reading the precursor to this and being a bit 'eh?', but now they've released a new article and I'm struggling to understand what the issue is with config.luas regarding screen resolutions.

 

 

In particular what are they trying to achieve with the variable set up?

They talk of doing this to enable using fullscreen backgrounds (of which they have several), but then you need to make your code work with variable sized windows (the idea of changing the resolution of an app just to match a background image strikes me as absurd).

 

I have what I believe to be a much simpler method, that works on any aspect ratio.

 

The core of the config.lua would be:

application =
{
    content =
    {
        width              = 320,
        height             = 480,
        scale              = "letterbox",
        xAlign             = "left",
        yAlign             = "top",
}

Naturally you'd add your image suffixes for content scaling as you want, and change the default resolution to whatever you want as the minimum area.

Now, how does this handle changing aspect ratios?

Well, it doesn't directly, but there-in lies the power. What it will do is stick a 320x480 area in the top left of your device display, stretched as big as possible without overlapping the borders (so you might get borders on the right side, or the bottom).

 

So now what? Well, it is easy. Just add the following code to your main.lua:

 

If running a portrait app:

_W   = math.floor( display.actualContentWidth + 0.5 )
_H  = math.floor( display.actualContentHeight + 0.5 )

 

If running a landscape app:

_W   = math.floor( display.actualContentHeight + 0.5 )
_H  = math.floor( display.actualContentWidth + 0.5 )

 

And now your globals _W and _H are the ACTUAL number of pixels you have for width and height, so instead of doing display.contentWidth you'd use _W etc. And... that's it really, it just works. Far simpler, and you are always working from at least one guaranteed size of axes.

 

 

I've been using this approach for ages now and never had any problems at all regardless of device resolution or aspect ratio, and I don't really get all the fuss about complicated config.lua.

 

Would welcome feedback, as I can't help feeling I'm missing something... :)

 



[TOPIC: post.html]
#2

Alex@Panc

[GLOBAL: userInfoPane.html]
Alex@Panc
  • Corona Geek

  • 1,733 posts
  • Corona SDK

I tried substituting your code above, and it make my screenview about 3 times what it normally is, causing all objects to be very small. The _W and _H didn't really set anything in the correct places either. 

 

If we originally patterned out config files after the "ultimate config.lua" post best practices, would we need to re-evaluate our code to fit your examples above?

Attached Thumbnails

  • normal.PNG
  • updated.PNG


[TOPIC: post.html]
#3

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

Well, did you set the width and height in the config.lua to what you want as your 'minimum'? I think most people nowadays assume a larger 'default' resolution but I still work at old iphone resolution and let content scaling take care of the rest.

 

Basically what my code will do is give you a resolution that is 0,0 in the top left, and extends to _W, _H, which will be the resolution closest to what you specify in the config.lua, while filling the entire screen and without distortion of aspect ratios.

 

What it does mean is you need to make your app position stuff relative to the _W, _H screen size, but my understanding of the ultimate config.lua file is that you end up with different resolutions depending on the device anyway - so using it your code must already handle variable resolutions.

 

If you set up the code as I have it above, then say you want to position something at the top right, it would be x, y = _W, 0. Bottom right would be x, y = _W, _H etc, which I figure most people are already doing (or some variant thereof), unless they are strictly using letterbox with borders.

 

I've never touched these config files, as they just seem too complicated for what they are trying to achieve, but I believe if your code already works on variable resolutions, then you'd just have to replace display.contentWidth with _W and display.contentHeight with _H throughout the project and it should just work.

 

If you had a simple example of a project using a complex config file you don't mind me looking at, I'd happily see what was required to make the change, so we could determine if it was actually worth it or not in general.



[TOPIC: post.html]
#4

Alex@Panc

[GLOBAL: userInfoPane.html]
Alex@Panc
  • Corona Geek

  • 1,733 posts
  • Corona SDK

Here are some updated screenshots showing the different in config files:

 

normal:

application =
{
	content =
	{
		width=320,
		height=480,
		fps = 60,
		scale = "letterbox",
	},
}

 

updated:

 

application =
{
    content =
    {
        width              = 320,
        height             = 480,
        scale              = "letterbox",
        xAlign             = "left",
        yAlign             = "top",
}

 

Seems kinda strange that it stretches so much even though basically nothing has changed. Whadda ya think?

Attached Thumbnails

  • normal.PNG
  • updated.PNG


[TOPIC: post.html]
#5

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

That is extremely odd - but then the first one isn't using any complicated config file.

In-game how do you calculate the width and height of the display - display.contentWidth etc?



[TOPIC: post.html]
#6

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

You used the other code I listed to create _W and _H right? Did you use the right one per landscape mode? It looks to me like it may have the _W and _H values mixed up - note for landscape you set _W to actualDisplayHeight, not width, and ditto for _H.



[TOPIC: post.html]
#7

Alex@Panc

[GLOBAL: userInfoPane.html]
Alex@Panc
  • Corona Geek

  • 1,733 posts
  • Corona SDK

On second look, I had a curly bracket out of place :( The "updated" config build looks the same as the "normal" build. 

 

I have another project I want to try this on, because if it works, I will have pulled all my hair out for nothing!



[TOPIC: post.html]
#8

craig stowers

[GLOBAL: userInfoPane.html]
craig stowers
  • Enthusiast

  • 42 posts
  • Corona SDK

I agree Rakoonic, and this is exactly how I do things. I would much rather work from the top left like I'm used to. Especially with all the headers and things like that. As long as you know the actual screen dimensions then people should size and place objects according to percentages of the _W & _H. Just makes more sense to me.

 

The only slight 'issue' I have with any scaling at all is that it can make pixel perfect alignment a slight issue. Maybe it's best not to scale at all and work completely with percentages of the actual resolution?



[TOPIC: post.html]
#9

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 25,935 posts
  • Enterprise

First of all, display.contentWidth and display.contentHeight are supposed to be read-only varaibles (see: http://docs.coronalabs.com/api/library/display/contentHeight.html).  You probably should not be trying to change them.  The display.actualContentHeight would seem to handle getting you the height of the content area including the letterBoxed bars and you could use that if needed, but other values like display.contentCenterX and display.contentCenterY are set based on display.contentWidth and display.contentHeight.  You in code have to change those values if you want to use them.

 

While you are an experienced programmer and understand the pitfalls of using globals and know when you can safely use them, that isn't the case for many of the developers out there.  We are trying to discourage usage of global variables and while _W and _H are handy short cuts, it's a better practice to use the values provided with the display object.

 

The beauty of Corona SDK is things like are not made of right and wrong ways to do things. You should use what works for you.  But with the wide level of skills helping the community solve a problem is an easy manner is a good thing.



[TOPIC: post.html]
#10

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

Rob - Yeah I would not recommend changing values like that either, and I was also hesitant about using the globals sample, but I've seen plenty of people using them.

Regarding the other values not being correct, you are right, but then again I never used them to be honest - I just needed to know the width and height and I do the rest myself. I just felt I was missing something because this config.lua thing is something I've seen raised many times in the past.

 

As for Corona (or rather Lua) having multiple ways of doing things I agree. I consider myself a reasonable programmer, but am new to Lua, and still learn new things all the time that makes me love it more and more :)

 

@craig - I have this issue in some games, where I want pixel perfect control. What I do in this case is have no scaling mode, and for front ends and menus etc I wrote my own alternative to content scaling. It works essentially the same, but the difference is you can toggle it on and off, so I get the best of both worlds.



[TOPIC: post.html]
#11

craig stowers

[GLOBAL: userInfoPane.html]
craig stowers
  • Enthusiast

  • 42 posts
  • Corona SDK

@Rob, I don't think anyone is changing those read-only variables. Just using them as a reference. Always referring to the _W & _H when sizing and placing elements on the screen (adding differences depending on which device) gives a developer more control imo, rather than sort of 'hoping for the best'.

 

But agreed, whatever is easier for each developer.

 

Also what is wrong with using just a few globals? Surely they don't take up too much memory, and as long as you don't keep making them throughout the app would it really matter? I would only create them when the app initializes (main.lua) and never create them on my "objects" (external scripts that a called multiple times) - I can definitely see why that would be an issue



[TOPIC: post.html]
#12

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

Craig I think the 'no globals' is best practice. I guess they try to hammer it home early on so people don't get accustomed to using them. I must admit I did use a few and then went down to one (I had a global table which is where I stored my 'globals'), before someone kindly posted code which removed the need for all globals but maintained the same functionality.

 

Here's the code - put it into a new lua file, call it globals.lua and you are almost ready.

local _data = {}
return data

To use it in any file you need globals just do something like:

local _myGlobals = require( "globals.lua" )
And that is it! You then just create and read globals by putting them into the _myGlobals variable, eg:

_myGlobals.playerLives = 10
print( _myGlobals.playerLives )
Simple 'globals' without any globals. I'd probably not use _myGlobals as a variable name, I soon tire of anything longer than a few characters!



[TOPIC: post.html]
#13

craig stowers

[GLOBAL: userInfoPane.html]
craig stowers
  • Enthusiast

  • 42 posts
  • Corona SDK

Right, I get that. but it still makes accessing these same variables between different objects a little difficult. Every time you 'require' that table, you are essentially resetting all the variables. I guess you could pass it as an argument into an objects 'new' function in order to keep referencing it.

 

 

But yeah, that data table would be fine for static variables.



[TOPIC: post.html]
#14

rakoonic2

[GLOBAL: userInfoPane.html]
rakoonic2
  • Contributor

  • 503 posts
  • Corona SDK

Craig, no, you don't reset the table.

The first time you require a file, it loads it into memory. However, future requires don't reload it, they merely pass a reference to the already-loaded module, which is why the values persist.



[TOPIC: post.html]
#15

craig stowers

[GLOBAL: userInfoPane.html]
craig stowers
  • Enthusiast

  • 42 posts
  • Corona SDK

Craig, no, you don't reset the table.

The first time you require a file, it loads it into memory. However, future requires don't reload it, they merely pass a reference to the already-loaded module, which is why the values persist.

 

Ah cool thanks for that. All my external scripts have tables created within function scopes, so I am used to doing things like: local newHeader = require("Classes.Objects.Header").new("titleHere"), and it of course would return a new 'instance'. I was not sure how the require operation actually operated itself.



[TOPIC: post.html]
#16

dgaedcke

[GLOBAL: userInfoPane.html]
dgaedcke
  • Contributor

  • 264 posts
  • Corona SDK

Does this technique get better or worse with Corona moving (in Graphics 2.0) to everything being created at center (rather than top/left) coordinates??  What are the pro's and conn's of Rob's ultimate config and this approach in terms of easy/intuitive display-object placement?



[TOPIC: post.html]
#17

ksan

[GLOBAL: userInfoPane.html]
ksan
  • Corona Geek

  • 2,795 posts
  • Corona SDK

Great question from @dgaedcke. Any comments on G2 compatibility with this approach? 



[TOPIC: post.html]
#18

primoz.cerar

[GLOBAL: userInfoPane.html]
primoz.cerar
  • Contributor

  • 455 posts
  • Corona SDK

I find this to be a good approach. I do a similar thing but I don't align the content to top left I just setup my own varibales for screenTop, screenBottom, screenWidth, screenHeight, screenCenter (changed by status bar or action bars) and other and then use those for positioning.



[TOPIC: post.html]
#19

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 25,935 posts
  • Enterprise

I don't think that G1.0 vs G2.0 has anything to do with The ultimate config.lua, though I guess things could be a bit easier.   For me when I started with Corona SDK, I was very confused because different things got positioned differently when you passed in the X, Y, the exact thing that G2.0 addressed so I got in a habit of explicitly setting the .x and .y after creating the object since I knew that was positioning by the center anyway.  With G2.0 I can now consistently position things and I'm trying to break the habit of explicitly setting the .x and .y, though I think the code is easier to read when I do. 

 

But regardless of the config.lua, this positioning works.  Where you have to think differently with the ultimate config.lua is positioning things in the middle of the screen or along the right and bottom edges.  Instead of using fixed numbers like x = 460 you have to use x = display.contentWidth - 20 and you have to be okay with edge positioned things relative distance of a fixed distance.  In other words for a landscape app, you might have a score near the right edge and the player's lives left near the left edge.  This lets you keep them a fixed distance form the edge vs. a fixed distance from each other.



[TOPIC: post.html]
#20

jesurn.co

[GLOBAL: userInfoPane.html]
jesurn.co
  • Observer

  • 3 posts
  • Corona SDK

Hey,

 

Rob and/or rakoonic, I could really use your help, guys!

 

I'm really frustrated due to the fact I haven't accomplished the "ultimate" config yet. I'm designing a game. I read both the ultimate config and modernizing the config articles created by Rob Miracle, but nothing really works. If I use rakoonic's method, do I still need image suffix? If so, exactly what types? 1.5 and 3.0? Does this mean I still need three different backgrounds (360x570, 720x1140, 1148x2280)? If so, using rakoonic's method, are the following lua files correct?

 

config.lua:

application =
{
    content =
    {
        width = 320,
        height = 480,
        scale = "letterbox",
        xAlign = "left",
        yAlign = "top",
        fps = 30,
 
        imageSuffix = -- 360x570
        {
            ["@2x"] = 1.5, -- 720x1140
            ["@4x"] = 3.0, -- 1148x2280
        },
    },
}

 

main.lua:

display.setStatusBar(display.HiddenStatusBar)
 
_W = math.floor(display.actualContentWidth + 0.5)
_H = math.floor(display.actualContentHeight + 0.5)
 
local background = display.newImageRect("textures/background.png", 360, 570) -- Is it correct, or is it 320x480?
background.anchorX = 1 -- Is it correct?
background.anchorY = 1 -- Is it correct?
background.x = _W -- Is it correct?
background.y = _H -- Is it correct?

 

If rakoonic's method is really working, I'd like to know if this is correct. If not, please tell me how.



[TOPIC: post.html]
#21

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 25,935 posts
  • Enterprise

Both of our systems work.  Your code will draw your background with the bottom right corner of the artwork at the bottom right corner of the device regardless of the shape of the device.  Depending on your artwork, this may be the the right thing or not.   You can do:

local background = display.newImageRect("textures/background.png", 360, 570) -- Is it correct, or is it 320x480?
background.anchorX = 0 -- Is it correct?
background.anchorY = 0 -- Is it correct?
background.x = 0 -- Is it correct?
background.y = 0 -- Is it correct?

 

And it will draw your artwork with its Top Left corner at the top left of the screen or you can do:

local background = display.newImageRect("textures/background.png", 360, 570) -- Is it correct, or is it 320x480?
background.anchorX = 0.5 -- Is it correct?
background.anchorY = 0.5 -- Is it correct?
background.x = _W / 2 -- Is it correct?
background.y = _H / 2 -- Is it correct?

 

And it will draw your background at the center of the screen.

 

Depending on your background and were important elements are, you may want to use any of the three ways to draw your background.  Just keep in mind that on some devices the bottom part of the screen will get cut off, on others the sides are going to get cut off.   Using centered, then some might get cut off of both sides. 

 

This graphic can help you  understand that's going on:

 

bleedarea.png

 

Now this assumes a center drawn background.  On an iPad you will get the yellow and blue areas on screen and the green and red will get cut off.  On an iPhone 5 or many Android phones, you will get the red and blue area visible while the green and yellow will be off screen.  If you're on an iPhone 3 or 4 you will only get the blue area.  Most Android tablets will loose some of the red, green and yellow, but keep some of it.

 

What you put in the red, green and yellow areas will determine the best placement strategy for you.   The Ultimate config.lua is based on these area's being centered on the screen.    0, 0 will be the top left.  display.contentWidth, display.contentHeight will be the bottom right corner and display.contentCenterX, display.contentCenterY will be the center.

 

Rakoonic's is accomplishing the same thing.  It's difference is that display.contentWidth, display.contentHeight return the defined values of 320 and 480 which may not be the actual content width and height.  This is why he uses the values display.actualContentWidth and display.actualContentHeight to create the shortcut's _W and _H.   At this point _W and _H represent the bottom right corner.  You have to calculate your own center values by dividing _W and _H by 2 (or multiply by 0.5) to compute your real centerX and centerY values.

 

As for the @2x and @4x things, you always load in the size of your smallest one.  In this case, 360x570 and you use the actual size of the image, not the content area.  That way the parts that need to bleed of the screen will and the artwork won't be distorted by changing it's aspect ratio.

 

Rob



[TOPIC: post.html]
#22

jesurn.co

[GLOBAL: userInfoPane.html]
jesurn.co
  • Observer

  • 3 posts
  • Corona SDK

Hey Rob,

 

First of all, thanks for responding and helping me! I really appreciate that, honest. Second, this is how my config.lua and main.lua are, at the moment. And yes, I have managed to center the background (there are no bleed areas). I use three different backgrounds (360x570, 720x1140, 1148x2280), just like you mentioned on your previous article (the ultimate config). These are my settings.

 

config.lua:

application =
{
    content =
    {
        width   = 320,
        height  = 480,
        scale   = "letterbox",
        xAlign  = "left",
        yAlign  = "top",
 
        imageSuffix =
        {
            ["@2x"] = 1.5,
            ["@4x"] = 3.0,
        },
    },
}

 

main.lua:

display.setStatusBar(display.HiddenStatusBar)
 
local storyboard = require("storyboard")
storyboard.gotoScene("scenes.start")

 

scenes/start.lua:

local storyboard = require("storyboard")
local scene = storyboard.newScene()
 
_W = math.floor(display.actualContentWidth + 0.5)
_H = math.floor(display.actualContentHeight + 0.5)
 
function scene:createScene(event)
    local sceneGroup = self.view
 
    local background = display.newImageRect("textures/background.png", 360, 570)
    background.x = _W / 2
    background.y = _H / 2
    sceneGroup:insert(background)
end
 
scene:addEventListener("createScene", scene)
 
return scene

 

I'm trying to be as organized as possible, so if you care to share your knowledge, please do. Everything works just fine, but just to be one hundred percent sure, do you find anything wrong? Anything at all?

 

Thanks once again, Rob. You are one helluva guy!



[TOPIC: post.html]
#23

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 25,935 posts
  • Enterprise

That seems to be doing what you need it to do.  Just keep in mind that display.contentWidth, display.contentHeight, display.contentCenterX, and display.contentCenterY values won't work for you.  You will have to use your calculated _W and _H and compute your own center's.

 

One completely off topic thought.  If you haven't downloaded 2189 yet, I would do so, and switch from Storyboard to Composer (It's storyboard 2.0).   http://coronalabs.com/blog/2014/01/21/introducing-the-composer-api-plus-tutorial/

 

It's going to be the scene manager that gets features and bug fixes going forward.  We are retiring storyboard.  If you are not too deep into it, switching now will be easier than later.  Same basic principles, just a cleaner API and a better code base for us to support long term.

 

Rob



[TOPIC: post.html]
#24

jesurn.co

[GLOBAL: userInfoPane.html]
jesurn.co
  • Observer

  • 3 posts
  • Corona SDK

Thanks for the heads up. I'll switch to composer.

 

By the way, why won't these displays work? Can you be more specific?

Also, you mentioned that I'll have to calculate the center point myself, do you mean _W / 2 for x, _H / 2 for y?

 

EDIT: I downloaded version 2189 and was wondering, when I use composer, it doesn't change the color to blue, like it's a function (it works, but the color remains white), is it because my corona editor package is not updated? If so, how do you I update it (i use sublime text)?



[TOPIC: post.html]
#25

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 25,935 posts
  • Enterprise

display.contentWidth and display.contentHeight return the value from your config.lua.  Since you only set 320 and 480, regardless of the device, that's the values returned.  That's why the method you are using is using display.actualContentWidth and display.actualContentHeight.  Likewise display.contentCenterX is display.contentWidth / 2, not display.actualContentWidth / 2.

 

Corona Editor has not been updated to know about composer yet.  This is to be expected.

 

Rob




[topic_controls]
Page 1 of 2 1 2
 
[/topic_controls]