This happens every time a composer.gotoScene is called.
Here is my code:
local function wave1( ) local sceneGroup = scene.view local function e1( ) --create enemy1 local enemy = display.newImageRect("images/enemy.png",50,25) enemy.x=-(screenW+enemy.contentWidth) enemy.y=0 enemy.name="enemy" physics.addBody(enemy, "dynamic", {density = 1, friction = 0, bounce = 0}) enemy.isSensor=true sceneGroup:insert(enemy) enemy:addEventListener('collision', collisionHandler) local function removeEnemy( self, event ) if (enemy ~=nil) then if (enemy.x \> display.contentWidth ) then Runtime:removeEventListener( "enterFrame", self ) display.remove(enemy) enemy=nil end end end enemy.enterFrame = removeEnemy Runtime:addEventListener( "enterFrame", enemy )
Pass in the group as a parameter worked for me in the function below:
function wave1(group) txt\_PlayGame = display.newText({ text = "Play Game", x = 375, y = 400, font = native.systemFontBold, fontSize = 48 }) group:insert(txt\_PlayGame) end
then from within your scene:create / scene:show whatever:
scene.view will be nil and that is why your code is failing as you cannot insert into nil.
Normally, you create your own display group(s) in scene:create( event ) and then insert your graphics into that (which puts them in the main scene by default).
How come scene.view is nil if it is declared as local sceneGroup = scene.view? Shouldn’t it be only nil if composer.removeScene(“scene”) is called?
Is the best way in managing your graphics is by putting it scene:create(event)? I put my waves of enemies outside scene:create(event) and inserting them directly to scene.view because its not behaving as I want to if I put it inside scene:create(event) (e.g. some enemies don’t load or does not gain a physics body).
Also I’m executing these waves of enemies in scene:show( event ) using timers like this:
function scene:show( event ) local sceneGroup = self.view if event.phase == "did" then physics.start() physics.setGravity(0, 0) transition.to( levelText, { time = 500, alpha = 0 } ) timerShip = timer.performWithDelay(1,createShip,1) timerW1 = timer.performWithDelay(3000,wave1,1) timerW2 = timer.performWithDelay(8000,wave2,1) timerW3 = timer.performWithDelay(11000,wave3,1) timerW4 = timer.performWithDelay(11000,wave4,1) timerW5 = timer.performWithDelay(13000,wave5,1) else -- event.phase == "will" currentScore = 0 currentScoreDisplay.text = string.format( "%06d", currentScore ) end end
and my scene:hide( event ) would look like this:
function scene:hide( event ) local sceneGroup = self.view if event.phase == "will" then timer.cancel( fireTimer ) timer.cancel( timerShip ) timer.cancel( timerW1 ) timer.cancel( timerW2 ) timer.cancel( timerW3 ) timer.cancel( timerW4 ) timer.cancel( timerW5 ) Runtime:removeEventListener("enterFrame", bgScroll)--remove listener for bg Runtime:removeEventListener( "enterFrame", blaster )--remove listener for enemy fire physics.stop() end end
scene:create() is for initialisation of all the objects needed for your scene. scene.show() is for finalisation of those objects. For example, you might load all your textures during create() but not use them until show().
I would advise having separate functions for object initialisation and passing a reference to the group.
So something like this (Note: this is very basic to show principles only)
local gameDisplayGroup = display.newGroup() -- this will hold all your sprites function scene:create( event ) local sceneGroup = self.view sceneGroup:insert(gameDisplayGroup) -- insert our game group into the main scene spawnEnemies(gameDisplayGroup) -- spawn enemies end function scene:show( event ) --prepare UI --trigger game start, etc end function spawnEnemies(group) --spawn enemies here and place into group end
This way you can loop gameDisplayGroup and get access to all of your sprites, apply effects and fills, etc. You might then have a UIDisplayGroup for your UI elements, etc. Think of your visual display as a group of stacked layers.
Because you are passing a display group to the spawnEnemies function, this function can reside in a different module
Pass in the group as a parameter worked for me in the function below:
function wave1(group) txt\_PlayGame = display.newText({ text = "Play Game", x = 375, y = 400, font = native.systemFontBold, fontSize = 48 }) group:insert(txt\_PlayGame) end
then from within your scene:create / scene:show whatever:
scene.view will be nil and that is why your code is failing as you cannot insert into nil.
Normally, you create your own display group(s) in scene:create( event ) and then insert your graphics into that (which puts them in the main scene by default).
How come scene.view is nil if it is declared as local sceneGroup = scene.view? Shouldn’t it be only nil if composer.removeScene(“scene”) is called?
Is the best way in managing your graphics is by putting it scene:create(event)? I put my waves of enemies outside scene:create(event) and inserting them directly to scene.view because its not behaving as I want to if I put it inside scene:create(event) (e.g. some enemies don’t load or does not gain a physics body).
Also I’m executing these waves of enemies in scene:show( event ) using timers like this:
function scene:show( event ) local sceneGroup = self.view if event.phase == "did" then physics.start() physics.setGravity(0, 0) transition.to( levelText, { time = 500, alpha = 0 } ) timerShip = timer.performWithDelay(1,createShip,1) timerW1 = timer.performWithDelay(3000,wave1,1) timerW2 = timer.performWithDelay(8000,wave2,1) timerW3 = timer.performWithDelay(11000,wave3,1) timerW4 = timer.performWithDelay(11000,wave4,1) timerW5 = timer.performWithDelay(13000,wave5,1) else -- event.phase == "will" currentScore = 0 currentScoreDisplay.text = string.format( "%06d", currentScore ) end end
and my scene:hide( event ) would look like this:
function scene:hide( event ) local sceneGroup = self.view if event.phase == "will" then timer.cancel( fireTimer ) timer.cancel( timerShip ) timer.cancel( timerW1 ) timer.cancel( timerW2 ) timer.cancel( timerW3 ) timer.cancel( timerW4 ) timer.cancel( timerW5 ) Runtime:removeEventListener("enterFrame", bgScroll)--remove listener for bg Runtime:removeEventListener( "enterFrame", blaster )--remove listener for enemy fire physics.stop() end end
scene:create() is for initialisation of all the objects needed for your scene. scene.show() is for finalisation of those objects. For example, you might load all your textures during create() but not use them until show().
I would advise having separate functions for object initialisation and passing a reference to the group.
So something like this (Note: this is very basic to show principles only)
local gameDisplayGroup = display.newGroup() -- this will hold all your sprites function scene:create( event ) local sceneGroup = self.view sceneGroup:insert(gameDisplayGroup) -- insert our game group into the main scene spawnEnemies(gameDisplayGroup) -- spawn enemies end function scene:show( event ) --prepare UI --trigger game start, etc end function spawnEnemies(group) --spawn enemies here and place into group end
This way you can loop gameDisplayGroup and get access to all of your sprites, apply effects and fills, etc. You might then have a UIDisplayGroup for your UI elements, etc. Think of your visual display as a group of stacked layers.
Because you are passing a display group to the spawnEnemies function, this function can reside in a different module