Add event listener error

I tried this :

function scene:create(event) local screenGroup = self.view local background = display.newImageRect("terrain.jpg",display.contentWidth,display.contentHeight) background.x = display.contentCenterX background.y = display.contentCenterY screenGroup:insert(background) ball = display.newImage("ball1.png") ball.x = 400 ball.y = 160 physics.addBody(ball, "dynamic") screenGroup:insert(ball) line = display.newImage("line.png") line.x = 80 line.y = 200 line:scale( 0.1, 0.2 ) physics.addBody(line, "static", {density=.1, friction=.2, radius=12}) screenGroup:insert(line) player = display.newImage("player.png") player.x = 100 player.y = 300 physics.addBody(player, "static", {density=.1, bounce=0.2, friction=.2, radius=12}) screenGroup:insert(player) function player:collision(event) if event.phase == "began" then transition.cancel() composer.gotoScene("restart", options) end end local function loopObject() local objectDown= function() transition.to(player, { time=1600, y=20, onComplete=loopObject }) end transition.to(player, { time=1600, y=300, onComplete=objectDown }) end loopObject() end

local function onCollision() if event.phase == "began" then if event.object1 == "ball" and event.object2 == "line" then print("Touched") end end end function scene:show(event) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then ball:addEventListener( "onCollision", onCollision) player:addEventListener("collision") Runtime:addEventListener("touch", onTouch) end end function scene:hide(event) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then print("hide removing objects") composer.removeScene( "start" ) ball:removeEventListener( "onCollision", onCollision ) player:removeEventListener("collision") Runtime:removeEventListener("touch", onTouch) display.remove( ball ) display.remove( player ) end end

When I tried the above code , nothing happened I didn’t get any errors . And then I did this code below :

ball:addEventListener( "onCollision") ball:removeEventListener( "onCollision")  

And I got this error :

ERROR: Runtime error addEventListener: listener cannot be nil: nil stack traceback: [C]: in function 'error' 10:58:37.860 ?: in function 'getOrCreateTable' 10:58:37.860 ?: in function 'addEventListener' 10:58:37.860 ?: in function 'addEventListener' 10:58:37.860 ?: in function 'addEventListener' 10:58:37.860 C:\Users\user\Documents\Corona Projects\app\game.lua:100: in function '?'

line 100 :

ball:addEventListener( "onCollision")

Clearly, you are having trouble understanding event listeners, I suggest you look through this tutorial in depth.

https://docs.coronalabs.com/api/event/collision/index.html

I tried this and still got no response :

local function onLocalCollision( self, event ) if(event.phase == "ended") then print( "Touched" ) end end function scene:show(event) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then ball.collision = onLocalCollision ball:addEventListener( "collision" ) player:addEventListener("collision") Runtime:addEventListener("touch", onTouch) end end function scene:hide(event) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then print("hide removing objects") composer.removeScene( "start" ) ball.collision = onLocalCollision ball:removeEventListener( "collision" ) player:removeEventListener("collision") Runtime:removeEventListener("touch", onTouch) display.remove( ball ) display.remove( player ) end end

I also tried it how it was in the example(s) but nothing changed .

hello

This is because you removed the object in phase == will when the screen disappears. And since you created the player in scene:create(), it will only be displayed once. The error is saying that it is trying to add an eventListener to an object that does not exist. 

EDIT: That was wrong, you need to have the player in scene:create().

Read this and it will help you fix it:

https://docs.coronalabs.com/guide/system/composer/index.html

No I have the player outside of create() . 

Still, this explains why your error is occurring.

I put the code into did and it’s still not working .

function scene:show(event) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then player:addEventListener("collision") Runtime:addEventListener("touch", onTouch) end end function scene:hide(event) local sceneGroup = self.view local phase = event.phase if ( phase == "will" ) then elseif ( phase == "did" ) then print("hide removing objects") composer.removeScene( "start" ) player:removeEventListener("collision") Runtime:removeEventListener("touch", onTouch) display.remove( ball ) display.remove( player ) end end

Did you at least look at the tutorial?

Yes I read it about 5 times and I don’t see what’s wrong

You should move the player code back into scene:create(). 

This was in the tutorial:

"The scene’s view is initialized and, if the view does not already exist, a create event is dispatched to the scene’s scene:create() function. At this point, the scene still resides “off screen,” so this is an opportune time to create user interface objects and other display objects needed for the scene, including buttons, text, graphics, and other objects that should show when the scene comes on screen."

Are you going to be needing the player for multiple levels? If you are, you should create a module that contains your player and its corresponding functions:

--player.lua local M = {} function M:new() --make character here function player:collision() --handles collision end function player:finalize() --Occurs when player is no longer needed (removes listeners) end end return M --scene.lua local player = require "player" player:new() --creates the player and attaches all of its listeners, it's that simple!

If you are not, then don’t do this, it is just extra work. However, if you are, consider this method, and if you want I can help you implement it.

This is what I get when I put the player code in the create scene :

game.lua:67: attempt to index local 'player' (a nil value)

This is my code :

local ball local player -- background function scene:create(event) local screenGroup = self.view local background = display.newImageRect("terrain.jpg",display.contentWidth,display.contentHeight) background.x = display.contentCenterX background.y = display.contentCenterY screenGroup:insert(background) player = display.newImage("player.png") player.x = 100 player.y = 300 player.myName = "player" physics.addBody(player, "static", {density=.1, bounce=0.2, friction=.2, radius=12}) screenGroup:insert(background) ball = display.newImage("ball1.png") ball.x = 400 ball.y = 160 physics.addBody(ball, "dynamic") ball.myName = "ball" screenGroup:insert(background) end

function player:collision(event) if event.phase == "began" then transition.cancel() composer.gotoScene("restart", options) end end

You need to define player:collision after player has been created within the scene:create function.

Otherwise at the point player:collision is defined, player is still nil. Remember, code runs top to bottom but code inside functions will not run until that function is called. Scene:create is not run until the very end of the file, after you try to define player:function.

An alternative is to have a local function called playerCollision, defined above scene:create, that is then assigned to player.

[lua]

player:addEventListener(“collision”,playerCollision)

[/lua]

So change onCollision to player collision or just write a separate function ?

Personally I would have a separate local playerCollision function. It’s easier to find and debug than something buried in scene:create.

I put this

local function playerCollision( event ) if event.phase == "began" then player = display.newImage("player.png") player.x = 100 player.y = 300 player.myName = "player" physics.addBody(player, "static", {density=.1, bounce=0.2, friction=.2, radius=12}) end end function scene:create(event) local screenGroup = self.view local background = display.newImageRect("terrain.jpg",display.contentWidth,display.contentHeight) background.x = display.contentCenterX background.y = display.contentCenterY screenGroup:insert(background) ball = display.newImage("ball1.png") ball.x = 400 ball.y = 160 physics.addBody(ball, "dynamic") ball.myName = "ball" screenGroup:insert(background) end

and now I’m getting this error :

C:\Users\user\Documents\Corona Projects\app\game.lua:74: attempt to index local 'player' (a nil value)

line 74 :

function player:collision(event) -- line 74 if event.phase == "began" then transition.cancel() composer.gotoScene("restart", options) end end

No. I said to create your player as normal within scene:create. After that, either add the player:collision function within scene:create now that player is in scope, or use addEventListener to add a listener for playerCollision, which must be defined above scene:create for that to be in scope.