What I was trying to do:
When running the completed version of the Star Fighter tutorial in the Corona Simulator, I was trying to move (drag) the ship on the screen immediately after pressing on the “Play” button, before the scene has totally faded in.
What I expected the result to be:
The ship to move
What happened instead:
Corona spits out the following error:
ERROR: Runtime error game.lua:159: attempt to perform arithmetic on field 'touchOffsetX' (a nil value) stack traceback: game.lua:159: in function '?' ?: in function \<?:190\>
- What version of Corona SDK you I am running and which version of Windows
- Corona Simulator 2018.3326 (2018.6.25)
- Windows 10 Version 1803
I guess it has something to do with this:
local function dragShip( event ) local ship = event.target local phase = event.phase if ( "began" == phase ) then -- Set touch focus on the ship display.currentStage:setFocus( ship ) -- Store initial offset position ship.touchOffsetX = event.x - ship.x elseif ( "moved" == phase ) then -- Move the ship to the new touch position ship.x = event.x - ship.touchOffsetX elseif ( "ended" == phase or "cancelled" == phase ) then -- Release touch focus on the ship display.currentStage:setFocus( nil ) end return true -- Prevents touch propagation to underlying objects end
Here is the whole code for the game.lua:
[spoiler]
local composer = require( "composer" ) local scene = composer.newScene() -- ----------------------------------------------------------------------------------- -- Code outside of the scene event functions below will only be executed ONCE unless -- the scene is removed entirely (not recycled) via "composer.removeScene()" -- ----------------------------------------------------------------------------------- local physics = require( "physics" ) physics.start() physics.setGravity( 0, 0 ) -- Configure image sheet local sheetOptions = { frames = { { -- 1) asteroid 1 x = 0, y = 0, width = 102, height = 85 }, { -- 2) asteroid 2 x = 0, y = 85, width = 90, height = 83 }, { -- 3) asteroid 3 x = 0, y = 168, width = 100, height = 97 }, { -- 4) ship x = 0, y = 265, width = 98, height = 79 }, { -- 5) laser x = 98, y = 265, width = 14, height = 40 }, } } local objectSheet = graphics.newImageSheet( "gameObjects.png", sheetOptions ) -- Initialize variables local lives = 3 local score = 0 local died = false local asteroidsTable = {} local ship local gameLoopTimer local livesText local scoreText local backGroup local mainGroup local uiGroup local explosionSound local fireSound local musicTrack local function updateText() livesText.text = "Lives: " .. lives scoreText.text = "Score: " .. score end local function createAsteroid() local randomAsteroidnr = math.random( 3 ) if ( randomAsteroidNr == 1 ) then randomAsteroidHeight = 102 randomAsteroidWidth = 85 elseif ( randomAsteroidNr == 2 ) then randomAsteroidHeight = 90 randomAsteroidWidth = 83 elseif ( randomAsteroidNr == 3 ) then randomAsteroidHeight = 100 randomAsteroidWidth = 97 end local newAsteroid = display.newImageRect( mainGroup, objectSheet, randomAsteroidnr, randomAsteroidheight, randomAsteroidwidth ) table.insert( asteroidsTable, newAsteroid ) physics.addBody( newAsteroid, "dynamic", { radius=40, bounce=0.8 } ) newAsteroid.myName = "asteroid" local whereFrom = math.random( 3 ) if ( whereFrom == 1 ) then -- From the left newAsteroid.x = -60 newAsteroid.y = math.random( 500 ) newAsteroid:setLinearVelocity( math.random( 40,120 ), math.random( 20,60 ) ) elseif ( whereFrom == 2 ) then -- From the top newAsteroid.x = math.random( display.contentWidth ) newAsteroid.y = -60 newAsteroid:setLinearVelocity( math.random( -40,40 ), math.random( 40,120 ) ) elseif ( whereFrom == 3 ) then -- From the right newAsteroid.x = display.contentWidth + 60 newAsteroid.y = math.random( 500 ) newAsteroid:setLinearVelocity( math.random( -120,-40 ), math.random( 20,60 ) ) end newAsteroid:applyTorque( math.random( -6,6 ) ) end local function fireLaser() -- Play fire sound! audio.play( fireSound ) local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 ) physics.addBody( newLaser, "dynamic", { isSensor=true } ) newLaser.isBullet = true newLaser.myName = "laser" newLaser.x = ship.x newLaser.y = ship.y newLaser:toBack() transition.to( newLaser, { y=-40, time=500, onComplete = function() display.remove( newLaser ) end } ) end local function dragShip( event ) local ship = event.target local phase = event.phase if ( "began" == phase ) then -- Set touch focus on the ship display.currentStage:setFocus( ship ) -- Store initial offset position ship.touchOffsetX = event.x - ship.x elseif ( "moved" == phase ) then -- Move the ship to the new touch position ship.x = event.x - ship.touchOffsetX elseif ( "ended" == phase or "cancelled" == phase ) then -- Release touch focus on the ship display.currentStage:setFocus( nil ) end return true -- Prevents touch propagation to underlying objects end local function gameLoop() -- Create new asteroid createAsteroid() -- Remove asteroids which have drifted off screen for i = #asteroidsTable, 1, -1 do local thisAsteroid = asteroidsTable[i] if ( thisAsteroid.x \< -100 or thisAsteroid.x \> display.contentWidth + 100 or thisAsteroid.y \< -100 or thisAsteroid.y \> display.contentHeight + 100 ) then display.remove( thisAsteroid ) table.remove( asteroidsTable, i ) end end end local function restoreShip() ship.isBodyActive = false ship.x = display.contentCenterX ship.y = display.contentHeight - 100 -- Fade in the ship transition.to( ship, { alpha=1, time=4000, onComplete = function() ship.isBodyActive = true died = false end } ) end local function endGame() composer.setVariable( "finalScore", score ) composer.gotoScene( "highscores", { time=800, effect="crossFade" } ) end local function onCollision( event ) if ( event.phase == "began" ) then local obj1 = event.object1 local obj2 = event.object2 if ( ( obj1.myName == "laser" and obj2.myName == "asteroid" ) or ( obj1.myName == "asteroid" and obj2.myName == "laser" ) ) then -- Remove both the laser and asteroid display.remove( obj1 ) display.remove( obj2 ) -- Play explosion sound! audio.play( explosionSound ) for i = #asteroidsTable, 1, -1 do if ( asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2 ) then table.remove( asteroidsTable, i ) break end end -- Increase score score = score + 100 scoreText.text = "Score: " .. score elseif ( ( obj1.myName == "ship" and obj2.myName == "asteroid" ) or ( obj1.myName == "asteroid" and obj2.myName == "ship" ) ) then if ( died == false ) then died = true -- Play explosion sound! audio.play( explosionSound ) -- Update lives lives = lives - 1 livesText.text = "Lives: " .. lives if ( lives == 0 ) then display.remove( ship ) timer.performWithDelay( 2000, endGame ) else ship.alpha = 0 timer.performWithDelay( 1000, restoreShip ) end end end end end -- ----------------------------------------------------------------------------------- -- Scene event functions -- ----------------------------------------------------------------------------------- -- create() function scene:create( event ) local sceneGroup = self.view -- Code here runs when the scene is first created but has not yet appeared on screen physics.pause() -- Temporarily pause the physics engine -- Set up display groups backGroup = display.newGroup() -- Display group for the background image sceneGroup:insert( backGroup ) -- Insert into the scene's view group mainGroup = display.newGroup() -- Display group for the ship, asteroids, lasers, etc. sceneGroup:insert( mainGroup ) -- Insert into the scene's view group uiGroup = display.newGroup() -- Display group for UI objects like the score sceneGroup:insert( uiGroup ) -- Insert into the scene's view group -- Load the background local background = display.newImageRect( backGroup, "background.png", 800, 1400 ) background.x = display.contentCenterX background.y = display.contentCenterY ship = display.newImageRect( mainGroup, objectSheet, 4, 98, 79 ) ship.x = display.contentCenterX ship.y = display.contentHeight - 100 physics.addBody( ship, { radius=30, isSensor=true } ) ship.myName = "ship" -- Display lives and score livesText = display.newText( uiGroup, "Lives: " .. lives, 200, 80, native.systemFont, 36 ) scoreText = display.newText( uiGroup, "Score: " .. score, 400, 80, native.systemFont, 36 ) ship:addEventListener( "tap", fireLaser ) ship:addEventListener( "touch", dragShip ) explosionSound = audio.loadSound( "audio/splat.wav" ) fireSound = audio.loadSound( "audio/fart1.wav" ) musicTrack = audio.loadStream( "audio/game.wav") end -- show() function scene:show( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is still off screen (but is about to come on screen) elseif ( phase == "did" ) then -- Code here runs when the scene is entirely on screen physics.start() Runtime:addEventListener( "collision", onCollision ) gameLoopTimer = timer.performWithDelay( 500, gameLoop, 0 ) -- Start the music! audio.play( musicTrack, { channel=1, loops=-1 } ) end end -- hide() function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then -- Code here runs when the scene is on screen (but is about to go off screen) timer.cancel( gameLoopTimer ) elseif ( phase == "did" ) then -- Code here runs immediately after the scene goes entirely off screen Runtime:removeEventListener( "collision", onCollision ) physics.pause() -- Stop the music! audio.stop( 1 ) composer.removeScene( "game" ) end end -- destroy() function scene:destroy( event ) local sceneGroup = self.view -- Code here runs prior to the removal of scene's view -- Dispose audio! audio.dispose( explosionSound ) audio.dispose( fireSound ) audio.dispose( musicTrack ) end -- ----------------------------------------------------------------------------------- -- Scene event function listeners -- ----------------------------------------------------------------------------------- scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) -- ----------------------------------------------------------------------------------- return scene
[/spoiler]
P.S. I tried to use the lua tags for pasting in lua code, but I couldn’t get it to work correctly - it didn’t show the indentations or line numbers when I preview the post.
Thanks for any help!