Auto-rotation question

Hi, I’m a newbie to the Corona SDK and to app programming in general.   I’ve been searching for an answer to a specific problem but couldn’t find it.   Anyways, my stupid question is, how do I handle auto-rotation in my app?  The problem is that if I rotate the display in my iPhone/iPad simulator, none of the elements move around to the new orientation, so the layout looks like a mess and only partially fills up the screen. 

I have everything (newRects, newFonts, etc.) relative to display.contentWidth and display.contentHeight, so nothing is hard-coded.

Do I add a runtime event listener for the ‘resize’ event? If so, then how do reset my entities (like newRect) to the new dimensions without creating a new entity (and hence eating memory)?

My build.settings is as follows:

settings = { orientation = { default = "", supported = { "landscapeLeft", "landscapeRight", "portrait", "portraitUpsideDown" }, }, }

Look at the orientation event.  You may need to redraw your user interface to work differently depending on the orientation.  All we  are going to do for you is rotate the stage accordingly.  All of your UI objects are going to be at the same X, Y that they were.

Rob

Thanks for your reply (and for all your other tips), Rob.

I’ve used the orientation event earlier to do something like the code below, which actually does rotate everything properly, but it will only work on scenes that never change :wink:   It calls createScene, which probably is not a smart idea because it does not clean up the previous scene.   So if I made changes to the scene, it will reset everything back to the way it was when I first called createScene.

Is this a step in the right direction?  How would I re-adjust my existing entities, like rectangles, to change their top/left parameters to the new content dimensions?

function changeOrientation( event ) print("changeOrientation") scene\_name = storyboard.getCurrentSceneName() scene = storyboard.getScene(scene\_name) scene:createScene(event) end Runtime:addEventListener( "orientation", changeOrientation )

I am just looking at this for my ‘completed’ business app.

I have found that just using Corona auto support does not do the job fully, but is close (for my listViews). Toolbars and navigation bars need re-drawing/re-positioning in my app.

I have created  display layout subroutines that are called in the  createScene  event and again in the orientation event.

These routines  get the display size and then call the  layout routines. This is probably easier in my case because it a set of ‘static’ scenes with no game aspects or sprites or moving objects except the listview scrolling (which seems to be managed ok by Corona) and button clicks. I think this could be difficult for a game app with sprites all over the screen, but not having that coding experience thats all I can add here.

I will be interested in gamers views and techniques as that is my next app using Perspective and Physics.

The simplest, I suspect  would be to restart the scene after a storyboard.removeScene(Currentscene) etc to clear out the prior  oriented scene. But probably not a satisfying approach for the player/user. In my app I just remove Objects before the re-drawing again.

Alec

PS After writing the above I found this deep in the forums that looks like it may answer a lot of questions outstanding

http://developer.coronalabs.com/code/proper-orientation-rotation-animation

Yeah, I found this is working for me as well now.   I simply call “display.remove()” on my newRect() or newText() objects, but keep the rest of the game data intact.   All I need to do is redraw those objects and everything seems to work upon rotation.

I just had to add the following to my scene file:

local function changeOrientation( event ) .. .. end Runtime:addEventListener( "orientation", changeOrientation )

EDIT:

In both my createScene() and changeOrientation() functions, they call the same layout routine (“drawEverything()”) as you mentioned.

function scene:createScene( event )   local group = self.view   drawEverything(group) end local function changeOrientation( event )   local group = scene.view drawEverything(group) end

My layout routine drawEverything() will check if a rotation occurred simply by doing this for every object (e.g. a rounded rect, a text object, etc.):

local my\_rect local function drawEverything(group) -- destroy existing rect if my\_rect then   display.remove(my\_rect) my\_rect = nil end   ... end

Then I proceed with the regular layout code in drawEverything() 

e.g.   

-- recalculate dimensions max\_x = display.contentWidth max\_y = display.contentHeight -- draw/redraw rect my\_rect = display.newRect(......) my\_rect:addEventListener(.....) group:insert(my\_rect) 

I still run into issues further on when I go away from the scene and then return to the scene, and then rotate it again.  At that point it says the group insert command has a nil value. Upon further inspection, it seems that the rotation caused the group value (scene.view) to be nil.  ??

EDIT:  Somehow this fixes the group variable so that it’s no longer nil.  I have no idea… but it works.

local function changeOrientation( event )   local group = scene.view      if group then     print("group is not nil")     drawEverything(group)   end end  

I found similar problems. In my case I had lost reference to the group(layer ) that the object was in,  due to jumping around routines and loosing reference (due possibly to scope of names and not passing parameters as I should have done) .

But mainly I have also found synch timing issues (i.e arriving at a routine/code before the actual ‘system’ (IOS,Corona) has completed it’s  event action(such as maybe the group not being completed or not quite ready for referencing), So I have had to put code in, all over the place, to always check for nil 's before continuing processing.

 You have ‘local group=scene.view’ so that keeps the addressability to the objects and passing that ‘group’ reference to drawEverything that routine can now ‘see’ the objects and handle them ok, but you now will only go there when the group is not nil. which is the safe way to write in this system based on limited experience.

The timing issues pop up all over the place e.g. a simple listview event ‘onRowRender’ can keep firing well after an object has been removed (queueing in IOS I suspect) so in that event I place checks to see if the listview object has not gone to nil before running through the processing of a Row… [Try testing a user fast button clicking and code gets re-run faster and all sorts of problems pop up as the events get queued. …]

These Corona/IOS structures and objects of graphic programming, understanding and  addressing different layers(groups)  and timing are new to me, but similar to past experience of other mutli-tasking systems;  so what I have commented on may not be 100%, others more experienced with Corona may give further and better feedback later.

I am pleased you have it working.

Alec

PS For my comments to be valid it would mean the Orientation event is getting fired more than once.

Looking back at your code check the scope of  your declaration ’ local my_rect’ as a possible error - make it a global temporarily to see it it runs ok then as well…

Hi dislam

ref your code… I am experiencing the same situation. However, when I looked deeper, when the code executes ok (not nil) , what has happened, in my case,  a ‘duplicate scene’ has been created over the top of the prior un- oriented scene. So for the moment I am lost and do not have a solution- Hopefully some of the Pro developers have a solution…

Somehow we need to remove the ‘prior scene group’ and then redraw the newly oriented group.Otherwise memory will be leaked(used) each time an orientation occurs.


local function changeOrientation( event )
  local group = scene.view
  
  if group then
    print(“group is not nil”)
    drawEverything(group)
  end


[quote name=“ibmprgmrsince1964” post=“218523” timestamp=“1386023256”]Hi dislam ref your code… I am experiencing the same situation. However, when I looked deeper, when the code executes ok (not nil) , what has happened, in my case,  a ‘duplicate scene’ has been created over the top of the prior un- oriented scene. So for the moment I am lost and do not have a solution- Hopefully some of the Pro developers have a solution… Somehow we need to remove the ‘prior scene group’ and then redraw the newly oriented group.Otherwise memory will be leaked(used) each time an orientation occurs.   ------------------------------------------------- local function changeOrientation( event )  local group = scene.view      if group then    print(“group is not nil”)    drawEverything(group)  end ---------------------------------------------------[/quote] Interesting, thanks for the update. How did you figure out it was a duplicate scene?

I have a listview  and when the listview was scrolled up too high I could see the other list behind. I also notice memory was increasing. (Another temporary way is to reduce the gamma value (setFillColor) and you can see through the top layer objects)

However,  I have found my problem , could be yours also be similar , it is related to scope of names.

In sceneA I have same code as yours

 function onOrientationChange( event )
    print ( “SceneA orientation occurred” ) --debug code in all my orientation routines !
    local group = scene.view
           --ClearThisSceneObjectsandRotate(group)
end
 --=======================================
Runtime:addEventListener( “orientation”, onOrientationChange )

–=====================================

In sceneA I also transfer to another scene sceneB

just before executing gotoscene(“sceneB”) I have Runtime:removeEventListener( “orientation”, onOrientationChange ).

But I noticed that sceneA orientation was still firing, even after executing the removing the event listener (I thought) and although changing orientation while showing  sceneB ,

sceneA still fired and fired first!

The problem is/was scope of names. The onOrientationChange routine was defined as local and was lower in the code than the

Runtime:removeEventListener( “orientation”, onOrientationChange ). The remove onOrientationChange==nil and was not shown up as an error!

Making a forward reference in the top section to onOrientationChange solved it for me and it all now works without the need for the test of group being nil!  (Keep it it as belt and braces!)

So the message for me is : continually, and thoroughly  check scope of names of variables and functions when things act strangely!!

Alec…

Thank you!   Making my onOrientation function without the ‘local’ keyword made the orientation change work without any added checks.  Wow, such a simple thing, but can be quite frustrating if done wrong and not understood!!

As a test, all you need to do is enter SceneA, leave SceneA (go to SceneB), go back to SceneA and then change the orientation.  At this point there should be no crash.

I guess this is the code that makes everything work properly so far:

function scene:createScene( event ) local group = self.view drawEverything(group) end function scene:exitScene( event ) Runtime:removeEventListener( "orientation", onChangeOrientation ) end function onChangeOrientation( event ) local group = scene.view drawEverything(group) end Runtime:addEventListener( "orientation", onChangeOrientation )

By the way, how did you notice the memory was increasing in the problem case?  

-Danial

Hmm… in once of my scenes, if I add the removeEventListener for “orientation”, then when I come back to the scene, I can no longer rotate the elements.  It doesn’t enter the onChangeOrientation function anymore in that scene.   If I remove the ‘removeEventListener’ line then the problem goes away and I can rotate properly.

All the other scenes are fine with orientation though.

EDIT:  Gah, nevermind.   I forgot to remove SceneA when I went to SceneB.

I needed to put the below code in SceneB.  Now when I go back to SceneA, it is able to add the event listener again for orientation.

function scene:enterScene( event )   storyboard.removeScene("SceneA") end  

Hi Daniel,

The removing of local on your function has now made that a Global and can be seen throughout the project.

As you have found, if you dont remove the scene ‘things’ hang about unexpectedly…

If you want to keep variable and functions local to say sceneA (so only sceneA knows about that particular name) then in sceneA some where at the top of the coding just write ‘local onOrientation’ and then it should still work.

This subject can, my view, be  a  subject that is like holding down a sack of snakes… (ie Globals vs Locals vs modules- do a google search and you will see numerous debates on what is right/wrong)

To start you off here are a couple of links (but a big subject to one’s  head around fully…)

http://www.coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

http://www.ludicroussoftware.com/blog/2012/01/16/scope-in-corona/

http://lua-users.org/wiki/LuaDirectory --look for scoping

— Removing scenes

There is a more generalised way of doing this, in case you don’t know the sequence of scenes the user might select.

I have a module that I put all my formatting in and require that in each of my scenes (my formatted scenes are similar) and call that on createScene…

–================================

function scene:createScene( event )

local group = self.view

    local Priorscene=storyboard.getPrevious ( )
                    if  Priorscene~= nil then
                        storyboard.removeScene(Priorscene)
                    end
FormatSceneDisplay(group)

-=====

SceneDisplayObjects.SceneStatus=“SceneA  creating”-- my internal footprinting to keep an eye on what is happening

print(SceneDisplayObjects.SceneStatus)                     

end

–===============================================

[Note: for debugging I push the following to a global in each function with the function name

[Sorry not a global- a module variable expose internally- separate subject]

SceneDisplayObjects.SceneStatus=“SceneA  creating”

SceneDisplayObjects.SceneStatus=“SceneA  WillEnter”

SceneDisplayObjects.SceneStatus=“SceneA Entered”

SceneDisplayObjects.SceneStatus=“SceneA Ending” and so-on…

You will see that at times things go ‘out of expected sequence’ such  as when one scene starts another might not end until after the scene you started . Just helps understand Corona a bit …

—========memory monitoring etc

In my Globals module that I require in main.lua before starting story boards scenes  I have this routine

----================MEMORY MONITOR=========
local function memUsage()
   collectgarbage(“collect”)
  _G.device.MemoryUsed = Utilities.roundToDecPlaces(collectgarbage( “count” ) ,2)-- alternate is maths.round(collectgarbage( “count” )
  _G.device.textureMemoryUsed=system.getInfo(“textureMemoryUsed”)
    if  oldmemoryCount~= _G.device.MemoryUsed then
           print( “Memory used”, _G.device.MemoryUsed, "   TEXTURE Used",_G.device.textureMemoryUsed/1048576)
           
   end

oldmemoryCount=_G.device.MemoryUsed

timer.performWithDelay( 4000, memUsage, 0 )
return _G
 

Good luck.

Alec

Great!  Thanks once again.  The global variable documentation was very useful.  I’ve cleaned up my main.lua and put the globals under mydata.lua.

Furthermore I’ve avoided the issue of mis-ordering functions by declaring them as variables at the top of the file so that they never return nil.

Now, one thing…  Regarding the PriorScene removal, I made a global function like this:

function M.removePreviousScene()      local old\_scene=storyboard.getPrevious()   if  old\_scene then     storyboard.removeScene(old\_scene)   end end  

I added it to all my createScenes:

function scene:createScene( event )   mydata.removePreviousScene()      local group = self.view   drawEverything(group) end  

However, I notice sometimes when going in and out of different scenes quickly, that the entering of the scene is delayed by a few seconds(!) now.   Any idea what is going on?

EDIT:  Actually… this might just be another issue. This scene generates some random data in one of its functions, and if it cannot find specific data then it re-generates the data until it’s happy.   That may be the issue here, nothing to do with the removal of scenes.

This is turning into quite an insightful thread for me!

It seems to me that you may have found the cause for the few seconds delay. It could well be the maths library and the calculation style you are using
e.g
Multiplication x*0.5 is faster than division x/2 .

x*x is faster than x^2

However, you might like to check also that you dont have too many print statements running as well, I have also found some widgets are a lot slower than others (Scrollview is a dog compared to Listview build- in terms of speed to create ) Take a look at the objects you are creating and the loops and put in a print time before and after, to narrow down the cause.
Here is a starter for tips.
http://www.coronalabs.com/blog/2013/03/12/performance-optimizations/
http://developer.coronalabs.com/content/performance-and-optimization
https://docs.coronalabs.com/guide/basics/optimization/index.html

Alec
Edit , Searching the forums here are animation calculation improvements discussed…

Just to round this thread off with latest testing. I have found the orientation can be very sensitive and redraws/flashes redrawing when in faceUp/faceDown and back again. So to stop this I have added code as follows

—=============================================
 function onOrientationChange( event )
    local group = scene.view

   _G.Orientation =event.type
    if OldOrientation~=  _G.Orientation and  _G.Orientation~=“faceUp” and  _G.Orientation~=“faceDown”  then
            SceneDisplayObjects.SceneStatus=“dashboard Orientated”  --app footprint for debugging
            OldOrientation=  _G.Orientation
            --print ( SceneDisplayObjects.SceneStatus )
            UnFormatSceneDisplay(group)
            FormatSceneDisplay(group)
    end
end
 --==============================================
Runtime:addEventListener( “orientation”, onOrientationChange )  --dont forget to remove this when change of scene!
–==============================================

Thanks, so did you buy the Pro version in order to test the Face Up/Down on your device?

Yeah I removed the orientation listener in my exitScene function.

.

I still running the free  SDK version. It shows and can see all orientation states ok on my iPhone 4.

Looks like I haven’t gotten that far yet, you are running it on your phone? I’m just using the sim and can’t see an option to do face up/down.

Correct, you only realise some things in real situations- Some apps are available to help test with the simulator to test such things as GPS, and I think the accelerometer, so if you search you may find something useful

Alec