Loading new levels

I may be having a big misunderstanding of how best to remove and reload levels.

I am using the Composer API in conjunction with LD. In my menu system which shuffle through scenes such as titlescreen to options menu and back or from title screen to levelselect then to the game I am able to use the myLevel:removeLeve() myLevel = nil code (in the:scene destroy function) and then have it reloaded in the scene:create function. In any scene that comes from another scene I call a removeScene command in the did phase of the scene:show of the current scene. This seems to work ok and the levels seem to reload.

I assuming my problem has to do with misunderstanding how the self.view and LD work together and how to make sure when I remove an object and want to reload it how to make sure its in the scenes view.

First some info on the actual game loop. I have two levels over lapping eachother 1) the level itself (platforms, player objects) and 2) the HUD (DPAD, buttons, etc) In the Scene:Create listener I load the level first and then the HUD so that the HUD is painted in the foreground.

Where I am running into the problem: My game loop, which is located in the scene:show “did” phase, runs on a runtime listener all other listeners (collision and touch) are in the create:scene listener. In the HUD there is a game pause button this calls a composer overlay scene. In this overlay I have two buttons at the moment, a back and a restart, the back button works as expected. It’s the restart that is causing me trouble. 

I have tried many ways to kill the scene and reload the level or to remove the level and reload it without killing the scene (technically I am removing 2 levels the level itself and the HUD)

Things I have tried: Having the restart listener in the overlay send a composer variable that flags inside the game loop that if this variable is true to remove the 2 levels and then run my loadLevelObjects() Function which is currently only called at the scene:create phase.

ie:

function scene:create( event )
application.LevelDirectorSettings.viewGroup = self.view
loadLevelObjects()

where loadLevelObjects looks like this:

function loadLevelObjects()

myLevel = LD:loadLevel(‘LevelNov3’)
    controlPanel = LD:loadLevel(‘controlPanelLev’)
    player = myLevel:getLayerObject(“Player”,“Player”).view

 

slideOffSensor = controlPanel:getLayerObject(“Controls”, “slideOff”).view
    slideOffSensor.isHitTestable = true

and many more objects …
  

In case it’s a question of scope (could this be the problem?) the loadLevelObjects functions is located after the scene:create and before the scene:show in the code.

So in my game loop I may have some sort of check such as:

if(restart) then

myLevel:removeLevel()

controlPanel:removeLevel()

myLevel = nil

controlPanel = nil

loadLevelOnjects()

restart = false

end

But this did not work. Whatever I try I end up with the same solution which seems to be the white screen left from removing the level. Actually if I remove only one of the levels they both seem to disappear.

The other tactic I have tried is killing the scene itself by using a intermediate scene from the overlay. So you click restart in the pause overlay and it goes to another scene called levelLoader in the scene:create it kills the game scene using removeScene and in the the games scene:destroy function I remove the 2 levels and make them nil. Then in the scene:show did phase of levelLoader  I call gotoScene on the game scene and hope this brings me back to the game. Ideally, in the game scene, this would start the create:scene and load the levels as it does in the first place. I have also tried many variants of these two techniques to no avail.

SO now that my essay is done, maybe you can help me figure out what I am doing wrong? I want a button in my game pause overlay to reload a level. (I don’t just want to reset variables because I have objects that disappear on collision that I want to return and do not want to load by hand - therefore  I want the whole level to reload fresh.)

I think I must not completely understand the scene view and how LD interacts because I was having a similar problem trying to remove and reload a layer object in the middle of a touch listener. Ie. I create a layerObject using the createLayerObject funtion I eventually call to remove the Object and then I try to create it again and it does not appear to work.

is my problem something to do with understanding the utility methods (copied from your documentation):
LD:removeLevel()

and

LD:cleanUP?

LD is the instance of the LD_loader and if I use the LD:removeLevel() as your documentation shows and I have two levels loaded how can I determine which level will be removed? should the LD not be a level object?

Ideally I want to remove only the myLevel LD Level and leave the HUD (controlPanel) on screen at all times. When I remove one it seems to remove both.

Any help would be fantastic, you have been very helpful in the past and I appreciate that. If you want more clarification or need more info let me know.

Hi,

This is actually a complicated task to achieve properly using composer (even without using LD).

You have to be very careful with your logic when trying to reload a scene because any variables defined in enter/create scene will not get performed again.

There is also a limitation with composer that you can’t load itself again without problems.

For my project I added a blank scene called levelSwitch which actually called the Game Scene or Play scene whatever you have called it.

This allowed the current game scene to unload and then levelSwitch would call it again.

The downside is that it clears the screen for one frame before reloading it.

Providing your code is worked correctly to restart within itself then in theory you should be fine which leads onto your question about unloading LD levels.

You unload a level by using the instance e.g.

GameLevel:removeLevel()

HUD:removeLevel()

If your reloading levels then cleanup is not required.

See if this helps.

thanks for the quick reply - I’ll review what I have done so far. It’s nice to hear that the intermediate scene idea works for you - I’ll pursue that further. 

Quick questions:

Is it possible to remove and load a level without changing scenes? ie. within my game scene is it possible to do Level:removeLevel() and then LD:LoadLevel(“Level”) and have it work?

I see in your example you used the intermediate scene technique, but where in the intermediate scene did you remove your game scene? ie. did you call the removeScene in the create or show portion? and where did you call the gotoScene(game) again? ie. in show? or hide?  Are you actually putting a delay of one frame? ie. using timer.performWithDelay()?

Lastly in your game scene where are killing the level? are you doing it in the destroy function?:

ie. the flow would go like this:

1)restart is clicked 

2)goto intermediate level loading scene

  1. somewhere either in create or show you are calling removeScene on the game scene.

  2. This triggers the scene destroy function in the game scene and  is this where you remove the level? By using level:removeLevel() and level -= nil.?

  3. Now that the game scene is killed somewhere else (later in show or hide?) in the intermediate level loading scene you are calling gotoScene(game) which reloads the scene and calls the create:scene in the game scene again? (or is this the problem the create scene doesn’t even load after the remove scene, but goes straight to show?) 

if this is correct then after step 5 your level should be reloaded as it was originally (making sure the variables are all cleaned up)

Lastly, do you ever remove the intermediate scene once you get back in the game scene? ie. do you call removeScene on the intermediate level Loader?

and one final LD question does removing an LD level also remove all the objects loaded from it?

ie. if I call either:

player = myLevel:getLayerObject(“Player”,“Player”).view

or

local armObjProps = {assetName = “hand_png”, x = -200,    y = -200, xScale = .5, yScale = .5}
    hand = myLevel:createObject(“Arm”,armObjProps).view

do these become nil after the level is destroyed? do I have to nil them myself? after the level is reloaded can I call them again as above?

Thanks again!

Yes you’re own the right track.

So the basic steps/events would be

  1. call switchLevel

EnterScene -> storyboard.removeScene(storyboard.getPrevious())

EnterScene -> storyboard.gotoScene(‘play’)

  1. play scene - events

EnterScene -> storyboard.removeScene(storyboard.getPrevious())

CreateScene -> application.LevelDirectorSettings.viewGroup = self.view

CreateScene -> myLevel = LD:loadLevel (“Level”… string.format("%02d", global.settings.level))

DestoryScene -> myLevel:removeLevel()

DestoryScene -> myLevel = nil

  1. play scene -> Restart Clicked

storyboard.gotoScene(‘switchLevel’)  – based on the above events this will load switchlevel, destory the play scene and reload it,

Try this, if I get time I’ll try and create an example.

I know you don’t need to always remove the previous scene but I ran into problems if I didn’t.

Also if you are using an overlay try and check for a return value in the play scene to then call switchLevel for example don’t call it from the overlay scene.

The removeLevel nils all LD internal references but not local instances (hand & player) so it is good practice to nil them in the destroy scene.

Like I said previously you could this without the switchLevel scene but you would need to structure your code well enough that it can clean itself up and restart everything nicely.

Let me know if this helps.

It did help. Thank you very much.

I have it working using an intermediate scene. Seems to work like a charm for now.

Level Director had a learning curve but now that I have most of the features down it’s very very powerful and helpful. Thanks again for making a great product and for taking time to help!

It’s much appreciated.

Although this is based on storyboard (easily adapted for composer) this might be useful if you want to reload without using the intermediate method;

http://coronalabs.com/blog/2013/08/20/tutorial-reloading-storyboard-scenes/

Excellent glad you got it working.

Level Director does have a learning curve but easy when you know how ;o)

I admit though, I do need to try and update the docs and tutorials. 

I may have spoke too soon. I am realizing now that my levels/objects are not being destroyed but just layered over top of each other which is wreaking havoc on many aspects of my game.

I think maybe my objects are not being destroyed because they are not properly being put in the composers scene view?

Can you tell me more about this line?
 

application.LevelDirectorSettings.viewGroup = self.view
 

it has bugged me from the start because I am not sure what its doing exactly (I have a guess that its setting a display group but in relation to composer what is it doing?)

and when i call

player = myLevel:getLayerObject(“Player”,“Player”).view

does the .view add the player object to the composers scene view? or do i need another display group? when i call the removeScene function is it killing the levels display group?

I may be having a similar problem as this:

http://forums.coronalabs.com/topic/52575-external-modules-reloading-everytime-i-re-enter-a-scene-urgent-deadline-related/

but since I am using LD and i am not 100% sure whats going on under the hood of the your library/ there is only a storyboard example and not a composer example I wonder if I am understanding everything correctly.

For example in your StoryBoard example project you have:

local screenGroup = self.view
    application.LevelDirectorSettings.viewGroup = self.view

in your scene1.lua, and:

local screenGroup = self.view
    application.LevelDirectorSettings.viewGroup = screenGroup

but you also never add any objects to the display group screenGroup

I am just wondering if you can explain to me whats actually happening here.

Which version are you using as there is a composer example with v2.81, if you don’t have it I will send it to you.

By setting leveldirectorSettings.viewGroup to the scene view tells LD that when it loads a level it needs to add the layers to this scene. All objects added to the layer will also be in the scene group. When you remove the scene it will remove the display groups but you also need to call the LD removeLevel function to delete all the internal objects.

If you’re still having problems then email me your project and I’ll take a look.

Hey thanks again for the help. I was wrong i do have the composer example I thought I just adapted it myself originally.

I am going to do my best to not have to send you my project. I do have one more question, and you touched on it earlier. Since remove Level only removes internal objects when I load objects using the myLevel:createLayerObject() and I wish to remove instances of these do i need to use the removeLayerObject() function or simply nil the object? or both? I am not sure if its my level objects that are loading twice or if its my player object because its firing off multiple collision events when I reload the level (it seems to fire off as many times as I try to reload the level)

 

Hi,

This is actually a complicated task to achieve properly using composer (even without using LD).

You have to be very careful with your logic when trying to reload a scene because any variables defined in enter/create scene will not get performed again.

There is also a limitation with composer that you can’t load itself again without problems.

For my project I added a blank scene called levelSwitch which actually called the Game Scene or Play scene whatever you have called it.

This allowed the current game scene to unload and then levelSwitch would call it again.

The downside is that it clears the screen for one frame before reloading it.

Providing your code is worked correctly to restart within itself then in theory you should be fine which leads onto your question about unloading LD levels.

You unload a level by using the instance e.g.

GameLevel:removeLevel()

HUD:removeLevel()

If your reloading levels then cleanup is not required.

See if this helps.

thanks for the quick reply - I’ll review what I have done so far. It’s nice to hear that the intermediate scene idea works for you - I’ll pursue that further. 

Quick questions:

Is it possible to remove and load a level without changing scenes? ie. within my game scene is it possible to do Level:removeLevel() and then LD:LoadLevel(“Level”) and have it work?

I see in your example you used the intermediate scene technique, but where in the intermediate scene did you remove your game scene? ie. did you call the removeScene in the create or show portion? and where did you call the gotoScene(game) again? ie. in show? or hide?  Are you actually putting a delay of one frame? ie. using timer.performWithDelay()?

Lastly in your game scene where are killing the level? are you doing it in the destroy function?:

ie. the flow would go like this:

1)restart is clicked 

2)goto intermediate level loading scene

  1. somewhere either in create or show you are calling removeScene on the game scene.

  2. This triggers the scene destroy function in the game scene and  is this where you remove the level? By using level:removeLevel() and level -= nil.?

  3. Now that the game scene is killed somewhere else (later in show or hide?) in the intermediate level loading scene you are calling gotoScene(game) which reloads the scene and calls the create:scene in the game scene again? (or is this the problem the create scene doesn’t even load after the remove scene, but goes straight to show?) 

if this is correct then after step 5 your level should be reloaded as it was originally (making sure the variables are all cleaned up)

Lastly, do you ever remove the intermediate scene once you get back in the game scene? ie. do you call removeScene on the intermediate level Loader?

and one final LD question does removing an LD level also remove all the objects loaded from it?

ie. if I call either:

player = myLevel:getLayerObject(“Player”,“Player”).view

or

local armObjProps = {assetName = “hand_png”, x = -200,    y = -200, xScale = .5, yScale = .5}
    hand = myLevel:createObject(“Arm”,armObjProps).view

do these become nil after the level is destroyed? do I have to nil them myself? after the level is reloaded can I call them again as above?

Thanks again!

Yes you’re own the right track.

So the basic steps/events would be

  1. call switchLevel

EnterScene -> storyboard.removeScene(storyboard.getPrevious())

EnterScene -> storyboard.gotoScene(‘play’)

  1. play scene - events

EnterScene -> storyboard.removeScene(storyboard.getPrevious())

CreateScene -> application.LevelDirectorSettings.viewGroup = self.view

CreateScene -> myLevel = LD:loadLevel (“Level”… string.format("%02d", global.settings.level))

DestoryScene -> myLevel:removeLevel()

DestoryScene -> myLevel = nil

  1. play scene -> Restart Clicked

storyboard.gotoScene(‘switchLevel’)  – based on the above events this will load switchlevel, destory the play scene and reload it,

Try this, if I get time I’ll try and create an example.

I know you don’t need to always remove the previous scene but I ran into problems if I didn’t.

Also if you are using an overlay try and check for a return value in the play scene to then call switchLevel for example don’t call it from the overlay scene.

The removeLevel nils all LD internal references but not local instances (hand & player) so it is good practice to nil them in the destroy scene.

Like I said previously you could this without the switchLevel scene but you would need to structure your code well enough that it can clean itself up and restart everything nicely.

Let me know if this helps.

It did help. Thank you very much.

I have it working using an intermediate scene. Seems to work like a charm for now.

Level Director had a learning curve but now that I have most of the features down it’s very very powerful and helpful. Thanks again for making a great product and for taking time to help!

It’s much appreciated.

Although this is based on storyboard (easily adapted for composer) this might be useful if you want to reload without using the intermediate method;

http://coronalabs.com/blog/2013/08/20/tutorial-reloading-storyboard-scenes/

Excellent glad you got it working.

Level Director does have a learning curve but easy when you know how ;o)

I admit though, I do need to try and update the docs and tutorials. 

I may have spoke too soon. I am realizing now that my levels/objects are not being destroyed but just layered over top of each other which is wreaking havoc on many aspects of my game.

I think maybe my objects are not being destroyed because they are not properly being put in the composers scene view?

Can you tell me more about this line?
 

application.LevelDirectorSettings.viewGroup = self.view
 

it has bugged me from the start because I am not sure what its doing exactly (I have a guess that its setting a display group but in relation to composer what is it doing?)

and when i call

player = myLevel:getLayerObject(“Player”,“Player”).view

does the .view add the player object to the composers scene view? or do i need another display group? when i call the removeScene function is it killing the levels display group?

I may be having a similar problem as this:

http://forums.coronalabs.com/topic/52575-external-modules-reloading-everytime-i-re-enter-a-scene-urgent-deadline-related/

but since I am using LD and i am not 100% sure whats going on under the hood of the your library/ there is only a storyboard example and not a composer example I wonder if I am understanding everything correctly.

For example in your StoryBoard example project you have:

local screenGroup = self.view
    application.LevelDirectorSettings.viewGroup = self.view

in your scene1.lua, and:

local screenGroup = self.view
    application.LevelDirectorSettings.viewGroup = screenGroup

but you also never add any objects to the display group screenGroup

I am just wondering if you can explain to me whats actually happening here.

Which version are you using as there is a composer example with v2.81, if you don’t have it I will send it to you.

By setting leveldirectorSettings.viewGroup to the scene view tells LD that when it loads a level it needs to add the layers to this scene. All objects added to the layer will also be in the scene group. When you remove the scene it will remove the display groups but you also need to call the LD removeLevel function to delete all the internal objects.

If you’re still having problems then email me your project and I’ll take a look.