Cant seem to delete a circle

Hi, I’m working on an explosion, and I cant seem to get rid of said explosion. Whenever I run my code, it always says that the object is already removed, though it clearly hasn’t. I can remove the listener without much problem.

    --Creates the explosion, pushing everything out of the circle (blastradius)     function setExplosion(self, event)         forceX = ( event.other.x - self.x  ) \* 3         forceY = ( event.other.y - self.y ) \* 3         event.other:applyForce(forceX, forceY, event.other.x, event.other.y)         timer.performWithDelay(10, function()         circle:removeEventListener("collision", circle)         circle:removeSelf()         end, 1)     end  

    --Draws the explosion radius     function drawExplosion(eventX, eventY)         return function()             circle = display.newCircle( eventX +20, eventY +20, 150 )                   circle.myName = "circle"                   game:insert(circle)             circle:setFillColor(100,100,100, 100)               physics.addBody( circle, "static", {isSensor = true} )               circle.collision = setExplosion               circle:addEventListener( "collision", circle )      end     end  

    --Execute on bomb collision     function onCollision(event)                  hit = true         timer.performWithDelay (10, drawExplosion(event.x, event.y) )                      bomb:removeEventListener("touch", circleTouched)             bomb:removeEventListener ( "collision", bomb )             bomb:removeSelf()          end  

    --Check if bomb hit     function checkHit(event)         hit = false         bomb.collision = onCollision         bomb:addEventListener( "collision", bomb )     end  

    --Shoot the bomb     function circleTouched(event)         if event.phase == "began" then              display.getCurrentStage():setFocus(bomb)         elseif event.phase == "ended" then                           bomb:applyLinearImpulse(event.xStart - event.x, event.yStart - event.y, bomb.x, bomb.y)                          -- with 250 timeout so no collission before airborn             timer.performWithDelay ( 250, checkHit  )             display.getCurrentStage():setFocus(nil)              end     end  

I just cant figure out why it gives me the error, saying that the object is already removed (the circle).

Which line of code does it say the error is on and what’s the exception printed in the console?

Oh right, in the setExplosion function, the circle:removeSelf() line

I can remove the listener just fine, but it gives me the following error on the removeSelf line:

ERROR: Attempt to remove an object that’s already been removed from the stage or whose parent/ancestor group has already been removed.

And I just cant figure out why it gives me this error, since I’m not doing anything with that group, nor have I removed it prior to that line.

You’re not drawing a circle, as far as I can tell.

This line:

timer.performWithDelay (10, drawExplosion(event.x, event.y) ) 

does not call drawExplosion and pass it any values. If you want to do what I think you want to do, you need to wrap the call to drawExplosion in a function because using a timer to call a function cannot pass parameters. Try replacing the line above with this:

timer.performWithDelay (10, function() drawExplosion(event.x, event.y) end)

That basically creates an anonymous function which gets called by the timer. The anonymous function can then execute as much code as it likes.

Once you’ve done this, you’ll see that the parameters being passed into the setExplosion function are valid, which allow the circle to be drawn. If the circle is never drawn, because the parameters to newCircle are invalid (in your case, nil) then calling :removeSelf() on the circle will not be possible.

But I did draw the circle, I’m doing so in the drawExplosion function. It’s my sensor field, or blast radius.

I tried replacing the line of code, but that seems to completely break the chain, and drawExplosion isnt even called anymore.

Can you provide your listing as it is, rather than broken up into segments?

I would highly recommend printing all your function parameter values at the start of each function, as I really think that the timer (while it may be calling ‘drawExplosion’) is not passing the values to drawExplosion that you think it is.

Look in the documentation for timer.performWithDelay - it states that the second parameter is a listener function. Specifically this means that you are passing a reference to a function, not a fully-formed command, to be called. So it is really important to understand that you can’t pass values to a function in the way you’re attempting.

http://docs.coronalabs.com/api/library/timer/performWithDelay.html

The funny thing is, you’re doing it just right in the first code fragment you’ve posted.

That actually is all the code related to the explosion, as well as shooting. I simply segmented it for the sake of readability.

I dont actually think the problem lies in the performWithDelay, since everything executes just fine. And actually, you can pass values in the way I do it, it was highlighted in one of the blog posts here on coronalabs.comhttp://www.coronalabs.com/blog/2012/05/02/faq-wednesday-3/ See question 3.

Yerp, ok, good point. Because the code was segmented I didn’t realise that’s what you’re doing. Though my point still stands, it’s just not relevant. You are calling a function and having a function reference returned, which the timer then calls.

So, now the problem is a question of scope. Where are you declaring the variable ‘circle’? I don’t see ‘local circle = nil’ anywhere and you are attempting to call a function on it above where, as far as I can see, you’re giving it a value.

Not sure if this actually works this way, but I’m drawing the circle in the drawExplosion function, and then remove that circle in the setExplosion function. The setExplosion function does come before drawExplosion, though it’s called after drawExplosion.

I do hope that makes sense, I’m not quite sure how to explain it. 

setExplosion - uses circle drawn from drawExplosion to push blocks away, also deletes said circle and listener.

drawExplosion - draws sensor circle as blastradius and then calls setExplosion.

I tried adding a local circle = nil at the start of the lua file, but that didn’t change anything.

I’ve had random problems with removeSelf() before - out of interest you could try display.remove(circle).

Sadly, still getting the same error. 

I pasted my entire code into pastebin: http://pastebin.com/FeSYQzpf

The problem is definitely related to not declaring the circle variable before you use it, but I think your code needs some restructuring anyway.

It’s difficult to run because I’m not sure what is calling this. Can you reduce this code listing to something a bit smaller which can run on its own, without images?

http://pastebin.com/qNW96YQ5

It’s not really reduced, since I wouldnt really know what to remove and keep, but I replaced all images with generic rectangles and circles.

And yeah, it really needs some restructuring.

Ok, well, I’ve got your code running on my machine. Add this to your code:

local removeSelfCalled = 0 --Creates the explosion, pushing everything out of the circle (blastradius) function setExplosion(self, event)     forceX = ( event.other.x - self.x  ) \* 3     forceY = ( event.other.y - self.y ) \* 3     event.other:applyForce(forceX, forceY, event.other.x, event.other.y)     timer.performWithDelay(10, function()         circle:removeEventListener("collision", circle)         removeSelfCalled = removeSelfCalled + 1         print("CALL REMOVE SELF",removeSelfCalled,circle,circle.parent)         circle:removeSelf()         circle = nil     end, 1) end  

and you’ll see that the timer fires twice, I expect because setExplosion gets called twice. I have figured out why, just yet.

I’ve just edited this post to set circle = nil This is because whenever you call removeSelf() you should always set the value of the variable to nil afterwards. This is also explained in many forums posts and blog posts.

I would work on finding out why the collision listener is being called twice, though that is one of the more (read: less) fun sides of debugging physics based code.

Huh… That’s indeed peculiar.

It does seem to remove the first one just fine, thankfully. So now its just solving the mystery of that second, non-existing circle.

There isn’t a second circle - there’s a second collision event, causing the collision listener to fire twice. Because you’ve got a really short timer firing the inner function, you need to have a ‘circle’ variable declared which you can set to nil on the first collision, then check if it nil on the second collision. The problem you’re facing is that the collisions are occurring very quickly and effectively fire within the 10 milliseconds between creating the timer and the timer listener being called.

It’s a fiddly problem, but just think about how you are handling the collision events and put some throttling code around it. You definitely, definitely need to declare your variables, or you run the risk of creating zombie values.

And I’ll just jump in here, since you mentioned the mystery of the non-existing second circle. Maybe variable scope is the culprit?

The “circle” variable seems to be a global. So every time drawExplosion is called, it assigns the newly created circle to “circle”. Perhaps the old circle was never properly removed and you just lost the reference to it and cannot remove it?

Oooooooh wait, I think see what I did wrong.

The setExplosion function is called for every target within the sensor field. So if there’s 5 blocks in that field, the function will be called 5 times! 

Now I simply moved the removal function to the drawExplosion function, and added a timer that is as long as I want my explosion to last (currently working on animations).

Thanks for the help guys! You helped me understand what went wrong :slight_smile:

Which line of code does it say the error is on and what’s the exception printed in the console?

Oh right, in the setExplosion function, the circle:removeSelf() line

I can remove the listener just fine, but it gives me the following error on the removeSelf line:

ERROR: Attempt to remove an object that’s already been removed from the stage or whose parent/ancestor group has already been removed.

And I just cant figure out why it gives me this error, since I’m not doing anything with that group, nor have I removed it prior to that line.