Problem with position of objects on 3GS

First off please don’t point out how foolish it was of us to get to this stage in development having never tested the game on a 3GS, we fully understand our stupid mistake :slight_smile:

Our problem is that on all resolutions our objects are positioned perfectly except on the 3GS which has the the contentScaleX and Y of 1.

This is our config.lua file.

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

In our engine all objects have their positions set in a scene layout file, to try to get things to work on all resolutions we have everything positioned as an offset from the centre of the screen. This has been working great so far on every device, until we tested on the 3GS. 

This is one of the scenes in the game working fine on the iPhone 4:

iphone4.png

And this is the same scene on the 3GS:

iphone3gs.png

As you can see, both the background image and the centre dial image are positioned correctly. Both of these have no offset set so they are both in the centre of the screen. The other 4 dials all have an offset specified and you can see they are no longer in the desired positions.

What we need is some kind of scaling factor we could apply to the positions so that they would be placed where they are supposed to be but I just can’t think of how I could do it without having it affect all other resolutions.

I can provide more code if required or an apk of the project to see it in action if that helps. I’m also going to try to simplify everything into a small demo.

Happy to say that I have now solved this.

To make our lives easier the engine is written so that if a width and height isn’t specified for images in the layout file then the engine will create the image, get the size, and then delete the image. This works fine for most images but our background images, which are 570x360, get read as 512x323 so end up being scaled. It’s actually that which is wrong and not the positions of the images.

All I had to do to fix it is pass in true as the last argument to display.newImage() to make sure they are loaded full screen and the proper sizes are retrieved.

Hi Graham,

Happy you solved the issue. Was just wandering if you could share some nuggets on how you use a layout file. I’m currently trying to build a UIManager class that reads layout json files for a data-driven approach (as UI programming is a nightmare and leads to really messy code); however I’m not currently happy with my setup - particularly adding custom callbacks for events and such and I tend to think I’m overdoing the solution.

If you’re not happy to share no worries, but just thought it would be an intriguing Corona discussion as all of CL’s tutorials promote an inline approach which I don’t think is the best idea.

Apologies for hi-jacking the thread.

No worries about hijacking the thread, it’s solved now so hijack away :slight_smile:

Essentially for each ‘scene’ in our adventure game we have a layout file and a script file. We also have a Scene and Layout class. When we create a Scene object we pass in the path to both the script file and layout file.

The Scene object then creates a Layout object by looping through all the sections in the Json file and creates an Element object. This probably sounds a lot more complicated than it is but it’s all pretty simple.

For example, this is the layout file for one of our scenes:
 

[{ "name":"back", "visual":{ "type":"image", "path":"back.jpg" } }, { "name":"curtain", "speech":"Description\_TownHall\_Curtain", "visual":{ "type":"shape", "x":-90, "y":-100, "width":"350", "height":250, "alpha":0.01 } }, { "name":"board", "scene":"townHallBoard", "visual":{ "type":"shape", "x":200, "y":-20, "width":190, "height":170, "alpha":0.01 } }, { "name":"box", "visual":{ "type":"shape", "x":-160, "y":60, "width":140, "height":100, "alpha":0.01 } }, { "name":"otherBox", "scene":"townHallOtherBox", "visual":{ "type":"shape", "x":20, "y":60, "width":140, "height":100, "alpha":0.01 } }]

Each element can have as much data as it wants and also a Visual element if it desires ( most will ). The Visual can have a type of Group, Image, Shape, Button, ToggleButton or Label ( with more to come when we need them ).

The script file then has access to the Scene object so it can access any element by name or all of them. Multiple elements can have the same name if we like so we can get them all by that name, for instance in the scene that the above screenshot is taken all the dials are called “dial”, below is the layout file for that scene:

 

[{ "name":"back", "visual":{ "type":"image", "path":"back.jpg" } }, { "name":"dial", "index":1, "rotations":[ 0, 45, 135, 180], "visual":{ "type":"image", "path":"dial.png", "x":-170, "y":5 } }, { "name":"dial", "index":2, "rotations":[0, 45, 135, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":-85, "y":5 } }, { "name":"dial", "index":3, "rotations":[0, 45, 135, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":2, "y":5 } }, { "name":"dial", "index":4, "rotations":[0, 45, 135, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":87, "y":5 } }, { "name":"dial", "index":5, "rotations":[0, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":172, "y":5 } } ]

The scene scripts also have functions like onElementPress, onElementTouch, onUpdate, onItemUse etc that all get called at the appropriate times.

We then have Callbacks that allow access to various parts of the engine such as Callbacks:Audio_PlaySound() and Callbacks:Inventory_AddItem().

Hopefully that makes some kind of sense but feel free to ask any questions you have, only too happy to share!

Happy to say that I have now solved this.

To make our lives easier the engine is written so that if a width and height isn’t specified for images in the layout file then the engine will create the image, get the size, and then delete the image. This works fine for most images but our background images, which are 570x360, get read as 512x323 so end up being scaled. It’s actually that which is wrong and not the positions of the images.

All I had to do to fix it is pass in true as the last argument to display.newImage() to make sure they are loaded full screen and the proper sizes are retrieved.

Hi Graham,

Happy you solved the issue. Was just wandering if you could share some nuggets on how you use a layout file. I’m currently trying to build a UIManager class that reads layout json files for a data-driven approach (as UI programming is a nightmare and leads to really messy code); however I’m not currently happy with my setup - particularly adding custom callbacks for events and such and I tend to think I’m overdoing the solution.

If you’re not happy to share no worries, but just thought it would be an intriguing Corona discussion as all of CL’s tutorials promote an inline approach which I don’t think is the best idea.

Apologies for hi-jacking the thread.

No worries about hijacking the thread, it’s solved now so hijack away :slight_smile:

Essentially for each ‘scene’ in our adventure game we have a layout file and a script file. We also have a Scene and Layout class. When we create a Scene object we pass in the path to both the script file and layout file.

The Scene object then creates a Layout object by looping through all the sections in the Json file and creates an Element object. This probably sounds a lot more complicated than it is but it’s all pretty simple.

For example, this is the layout file for one of our scenes:
 

[{ "name":"back", "visual":{ "type":"image", "path":"back.jpg" } }, { "name":"curtain", "speech":"Description\_TownHall\_Curtain", "visual":{ "type":"shape", "x":-90, "y":-100, "width":"350", "height":250, "alpha":0.01 } }, { "name":"board", "scene":"townHallBoard", "visual":{ "type":"shape", "x":200, "y":-20, "width":190, "height":170, "alpha":0.01 } }, { "name":"box", "visual":{ "type":"shape", "x":-160, "y":60, "width":140, "height":100, "alpha":0.01 } }, { "name":"otherBox", "scene":"townHallOtherBox", "visual":{ "type":"shape", "x":20, "y":60, "width":140, "height":100, "alpha":0.01 } }]

Each element can have as much data as it wants and also a Visual element if it desires ( most will ). The Visual can have a type of Group, Image, Shape, Button, ToggleButton or Label ( with more to come when we need them ).

The script file then has access to the Scene object so it can access any element by name or all of them. Multiple elements can have the same name if we like so we can get them all by that name, for instance in the scene that the above screenshot is taken all the dials are called “dial”, below is the layout file for that scene:

 

[{ "name":"back", "visual":{ "type":"image", "path":"back.jpg" } }, { "name":"dial", "index":1, "rotations":[ 0, 45, 135, 180], "visual":{ "type":"image", "path":"dial.png", "x":-170, "y":5 } }, { "name":"dial", "index":2, "rotations":[0, 45, 135, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":-85, "y":5 } }, { "name":"dial", "index":3, "rotations":[0, 45, 135, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":2, "y":5 } }, { "name":"dial", "index":4, "rotations":[0, 45, 135, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":87, "y":5 } }, { "name":"dial", "index":5, "rotations":[0, 180, 225, 315], "visual":{ "type":"image", "path":"dial.png", "x":172, "y":5 } } ]

The scene scripts also have functions like onElementPress, onElementTouch, onUpdate, onItemUse etc that all get called at the appropriate times.

We then have Callbacks that allow access to various parts of the engine such as Callbacks:Audio_PlaySound() and Callbacks:Inventory_AddItem().

Hopefully that makes some kind of sense but feel free to ask any questions you have, only too happy to share!