attempt to call method 'removeSelf' (a nil value) help?

Hi,

Ive been trying to solve the issue that I stated in the title. The exact error in corona is

main.lua 136: attempts to call method ‘removeSelf’(a nil value) stack traceback

main.lua136:in function ‘_listener’

?: in function <?167>

?:in function <?169>

Any help would be great thanks.

function startGame(tapHandlerFn) splashScreen.isVisible = false sound1.isVisible = false sound2.isVisible = false level1.isVisible = true dpad.dSwitch(true) end local bg = display.newImageRect( level1, "assets/background.png", W\*4, H) bg.x = W/2 bg.y = H/2 - 50 bg:scale(1.2,1.2) local bg = display.newImageRect( level1, "assets/background.png", W\*4, H) bg.x = W/2 - 1450 bg.y = H/2 - 50 bg:scale(1.2,1.2) local bg = display.newImageRect( level1, "assets/background.png", W\*4, H) bg.x = W/2 + 1450 bg.y = H/2 - 50 bg:scale(1.2,1.2) local floor = display.newRect(level1, W/2, H, W\*100, 20) floor:setFillColor( 0, 0, 0 ) physics.addBody( floor, "static", {density=1.0, friction=0.02, bounce=0.2} ) local zombie = require("zombie") zombieShape = {-50,-90, 50,-90, 40, 95, -40,95} physics.addBody( zombie, {density=5.0, friction=.05, bounce=0.2, shape=zombieShape} ) zombie.x = W/2 + 50 zombie.y = H/2 + 140 zombie:scale(.5,.5) zombie.type = "zom" level1:insert(zombie) local player = require("player") playerShape = {-75,-75, 75,-75, -50, 90, 50, 90} physics.addBody( player, {density=1.0, friction = 0.02, bounce=0.2, shape=playerShape} ) player.x = W/2 - 300 player.y = H/2 + 100 player:scale(.4,.4) level1:insert(player) local gun = display.newImageRect( level1, "assets/ak-47.png", 150, 50) local function keyHandler(event) if(event.keyName == "space") then if(event.phase == "down") then shoot() else end end end function shoot() local function collided(event) local function listener(event) zombie:removeSelf() end if(event.other.type=="zom") then zombie:setSequence("dead") zombie:play() timer.performWithDelay( 1000, listener ) else end end local new\_bullet = display.newCircle( level1, gun.x + 80, gun.y - 17, 5 ) local function move\_bullet() new\_bullet.x = new\_bullet.x + 30 if(new\_bullet.y \< 0) then new\_bullet:removeSelf( ) else timer.performWithDelay( 30, move\_bullet , 1 ) end end physics.addBody( new\_bullet, "dynamic" ) new\_bullet.isSensor = true new\_bullet.gravityScale = 0 new\_bullet:addEventListener("collision", collided) timer.performWithDelay( 33, move\_bullet , 1 ) end function onRedraw(event) player.rotation = 0 local vx, vy = player:getLinearVelocity() local onGround = (vy \< 2) and (vy \> -2) player:applyForce( (dpad.x\_touch \* 50), 0, player.x, player.y ) if(dpad.x\_touch \> 0) then player.xScale = .4 gun.xScale = 1 elseif(dpad.x\_touch \< 0) then player.xScale = -.4 gun.xScale = -1 end if (onGround) then if((vx \> 2) or (vx \< -2)) then if(player.sequence~="walk") then player:setSequence("walk") player:play() end else if(player.sequence~="idle") then player:setSequence("idle") player:play() end end elseif(vy \> 10) then --falling player:setSequence("idle") player:play() else -- player is moving up -- do nothing because jump took care of it? end if (dpad.a\_touched) then -- jump button pressed if(onGround) then player:applyForce( 0, -5000, player.x, player.y ) if(player.sequence~="jump") then player:setSequence("jump") player:play() end end end local apparent\_x = player.x + level1.x if(apparent\_x \> RIGHT\_BOUND) then level1.x = level1.x - (apparent\_x - RIGHT\_BOUND) elseif(apparent\_x \< LEFT\_BOUND) then level1.x = level1.x + (LEFT\_BOUND - apparent\_x) end gun.x = player.x gun.y = player.y + 50 end Runtime:addEventListener( "enterFrame", onRedraw ) Runtime:addEventListener( "key", keyHandler ) start:addEventListener( "tap", startGame ) dpad.toFront()

Hello! Can you format your code using “<>” button in the forum interface or insert “[lua”]" (remove “”) at start and “[/“lua”]” (again, remove “”) at the end of code? It would be easier to follow and solve the problem.

Can you sum up your code and remove all useless line of code who won’t help us to correct the bug?

Like this one (I ask that to help you but it’s perhaps not the better idea, it’s only hard to take time to read all this line)

if(dpad.x\_touch \> 0) then player.xScale = .4 gun.xScale = 1 elseif(dpad.x\_touch \< 0) then player.xScale = -.4 gun.xScale = -1 end

Thank you!!! I am new the site and did not know how to do that

This is for my turning field which when the player turns it will reposition the player and the gun 90 degrees.

Sorry but when I ask to sum up it was to delete all line who can’t create the bug

Yep, we will need the part where the bug happens and an explanation of how it happens.

@tcglendinning:

I can’t be 100% certain that this is the line that is throwing the particular error you mentioned, but it’s a possibility (and it’s an opportunity to learn and improve upon your Corona/Lua coding habits):

The line in question is in your “collided” function, and in particular the nested “listener” function. In it, you call:

zombie:removeSelf()

This in and of itself is not a huge problem - as long as the variable “zombie” refers to a Corona display object, calling that line will remove the object. However, once an object has been removed, its “removeSelf” method is nil’ed out, so any attempt to call that method again will cause an error. First I’m going to point to the likely reason that this is getting called more than once, and then I’ll make a suggestion for your general coding habits.

First, why it’s getting called twice: physics collisions fire off multiple events per collision. Not unlike touch listeners can and should listen for the “event.phase” to indicate that a touch has begun or ended, physics collisions also have “began” and “ended” phases. The way your code is structured, the “collided” function will repeat itself on each collision because you don’t check for the event phase. You can fix this like this:

local function collided(event) local function listener(event) zombie:removeSelf() end if(event.other.type=="zom") and event.phase == "began" then zombie:setSequence("dead") zombie:play() timer.performWithDelay( 1000, listener ) else end end

More info on the event.phase parameter of collision events can be found here: https://docs.coronalabs.com/daily/api/event/collision/phase.html

Now for a more general suggestion that will help reduce errors: I personally almost never use the :removeSelf() method to remove display objects, precisely because it can throw an error if for whatever reason the object in question doesn’t exist or doesn’t have a removeSelf method attached. There is another global function **display.remove() **that does precisely the same thing as removeSelf, except you can safely call it without worrying about throwing an error. If the object you pass into display.remove doesn’t exist, or doesn’t have a removeSelf method attached, then nothing happens, and no error is thrown. But if the object you pass in can be removed safely, then it is. In your specific case, you’d replace “zombie:removeSelf()” with:

display.remove(zombie)

Now, one last suggestion - your code suggests that you could have a scope problem on your hands if you’re not careful. It could be that we’re not seeing the whole picture, but you create the zombie with a local variable called “zombie.” If that zombie is the ONLY zombie in the scene, then that’s potentially okay. But if you create multiple zombies, and you re-use that zombie variable, then you’d lose a way of easily referring to the previously-created zombies. And specifically, your collision listener will only remove the last zombie you created, since you explicitly refer to the “zombie” variable. A more flexible way of structuring your “collided” function would be this:

local function collided(event) local phase = event.phase local other = event.other local function listener() display.remove(other) end if other.type=="zom" and phase == "began" then other:setSequence("dead") other:play() timer.performWithDelay( 1000, listener ) else end end

This way your function is not dependent upon variables that exist outside of the scope of the function - it only refers to objects passed in via the event table.

Some of this advice wasn’t asked for (sorry), but hopefully it’ll help solve your problem and give you some useful tips as you keep moving forward. Good luck with your game! :slight_smile:

Good advice and all traps we have all fallen into along the way :slight_smile:

Thank you so much for this explanation! I am using this code for my gaming final and have been stuck on this particular point for a while. The step by step advice was great, it really helped.

Hello! Can you format your code using “<>” button in the forum interface or insert “[lua”]" (remove “”) at start and “[/“lua”]” (again, remove “”) at the end of code? It would be easier to follow and solve the problem.

Can you sum up your code and remove all useless line of code who won’t help us to correct the bug?

Like this one (I ask that to help you but it’s perhaps not the better idea, it’s only hard to take time to read all this line)

if(dpad.x\_touch \> 0) then player.xScale = .4 gun.xScale = 1 elseif(dpad.x\_touch \< 0) then player.xScale = -.4 gun.xScale = -1 end

Thank you!!! I am new the site and did not know how to do that

This is for my turning field which when the player turns it will reposition the player and the gun 90 degrees.

Sorry but when I ask to sum up it was to delete all line who can’t create the bug

Yep, we will need the part where the bug happens and an explanation of how it happens.

@tcglendinning:

I can’t be 100% certain that this is the line that is throwing the particular error you mentioned, but it’s a possibility (and it’s an opportunity to learn and improve upon your Corona/Lua coding habits):

The line in question is in your “collided” function, and in particular the nested “listener” function. In it, you call:

zombie:removeSelf()

This in and of itself is not a huge problem - as long as the variable “zombie” refers to a Corona display object, calling that line will remove the object. However, once an object has been removed, its “removeSelf” method is nil’ed out, so any attempt to call that method again will cause an error. First I’m going to point to the likely reason that this is getting called more than once, and then I’ll make a suggestion for your general coding habits.

First, why it’s getting called twice: physics collisions fire off multiple events per collision. Not unlike touch listeners can and should listen for the “event.phase” to indicate that a touch has begun or ended, physics collisions also have “began” and “ended” phases. The way your code is structured, the “collided” function will repeat itself on each collision because you don’t check for the event phase. You can fix this like this:

local function collided(event) local function listener(event) zombie:removeSelf() end if(event.other.type=="zom") and event.phase == "began" then zombie:setSequence("dead") zombie:play() timer.performWithDelay( 1000, listener ) else end end

More info on the event.phase parameter of collision events can be found here: https://docs.coronalabs.com/daily/api/event/collision/phase.html

Now for a more general suggestion that will help reduce errors: I personally almost never use the :removeSelf() method to remove display objects, precisely because it can throw an error if for whatever reason the object in question doesn’t exist or doesn’t have a removeSelf method attached. There is another global function **display.remove() **that does precisely the same thing as removeSelf, except you can safely call it without worrying about throwing an error. If the object you pass into display.remove doesn’t exist, or doesn’t have a removeSelf method attached, then nothing happens, and no error is thrown. But if the object you pass in can be removed safely, then it is. In your specific case, you’d replace “zombie:removeSelf()” with:

display.remove(zombie)

Now, one last suggestion - your code suggests that you could have a scope problem on your hands if you’re not careful. It could be that we’re not seeing the whole picture, but you create the zombie with a local variable called “zombie.” If that zombie is the ONLY zombie in the scene, then that’s potentially okay. But if you create multiple zombies, and you re-use that zombie variable, then you’d lose a way of easily referring to the previously-created zombies. And specifically, your collision listener will only remove the last zombie you created, since you explicitly refer to the “zombie” variable. A more flexible way of structuring your “collided” function would be this:

local function collided(event) local phase = event.phase local other = event.other local function listener() display.remove(other) end if other.type=="zom" and phase == "began" then other:setSequence("dead") other:play() timer.performWithDelay( 1000, listener ) else end end

This way your function is not dependent upon variables that exist outside of the scope of the function - it only refers to objects passed in via the event table.

Some of this advice wasn’t asked for (sorry), but hopefully it’ll help solve your problem and give you some useful tips as you keep moving forward. Good luck with your game! :slight_smile:

Good advice and all traps we have all fallen into along the way :slight_smile:

Thank you so much for this explanation! I am using this code for my gaming final and have been stuck on this particular point for a while. The step by step advice was great, it really helped.