Draw Physics Circle Upon Collision

I’m trying to create a Angry Bird-esque game where you fling a bomb to a structure. Upon collision, the bomb should explode, create a explosion field that pushes any object caught in it in a certain direction, depending on its location in comparison to the explosion’s center.

I’ve got the code I need, but I ran into a limitation of Corona, which is that I cant alter or do anything with the physics engine while Corona is “number crunching”

I wanted to draw a static circle, with isSensor set to true, to act as the explosion radius.

My relevant code:

My code for shooting the bomb

--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)                          timer.performWithDelay ( 250, checkHit  )             display.getCurrentStage():setFocus(nil)              end     end  

Code that checks if the bomb collided with something:

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

Spawning the “explosion” (currently the circle should be visible, for testing purposes):

--Execute on bomb collision     function onCollision(event)         hit = true         bomb:removeEventListener("touch", circleTouched)         bomb:removeEventListener ( "collision", bomb )         bomb:removeSelf()                  circle = display.newCircle( event.x, event.y, 80 )               circle.myName = "circle"           circle:setFillColor(100,100,100, 100)           physics.addBody( circle, "static", {isSensor = true} )           circle.collision = onLocalCollision           circle:addEventListener( "collision", circle )                    end  

The code for the explosion itself hasnt been written yet, but that shouldn’t (hopefully) be much of a problem.

Is there any way I can still create an explosion in a way like I envisioned, or am I forced to take a completely different approach? 

Hi @tomas_buiting,
 
The one issue you mention is common and easily solved. As you see, certain things regarding physics collisions can’t be done while the system is “number crunching”. The solution is to trigger your action after an unnoticeable 10 millisecond timer, so the action occurs in the next “game cycle”:
 
[lua]
–in collision handler:

timer.performWithDelay( 10, explodeBomb, 1 )
[/lua]
 
As for your specific “bomb exploding” action, it might not give you the desired result to just set a big radial object to non-sensor. If the objects inside the sensor suddenly have to treat that object as “solid”, they might go flying off in all kinds of crazy, unbelievable force vectors. However, it’s worth a try. I might have a more comprehensive solution for you, but first try the above approach and see what happens.
 
Best regards,
Brent

Even with that miniature pause, I’m still getting that “error” I’m not quite sure why it’s still giving me that, since I remove the bomb from the stage before calling the explosion function.

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

As for my explosion, what I had in mind was this:

&nbsp;&nbsp;&nbsp;&nbsp;function setExplosion(self, event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local forcex = event.other.x-self.x &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local forcey = event.other.y-self.y-20 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(forcex \< 0) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 0-(80 + forcex)-12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 80 - forcex+12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.other:applyForce( forcex, forcey, self.x, self.y ) &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

Also, note that my radial object is actually set as a sensor, not a non-sensor.

Hi tomas,

It’s still giving you the “can’t do [something] while number crunching” error? That’s very odd. Can you post what your “drawExplosion()” function looks like and where it’s scoped in your  code? Is it above the “onCollision()” function as a local function?

Brent

All my code related to the explosion and collision:

&nbsp;&nbsp;&nbsp;&nbsp;function setExplosion(self, event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local forcex = event.other.x-self.x &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local forcey = event.other.y-self.y-20 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(forcex \< 0) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 0-(80 + forcex)-12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 80 - forcex+12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.other:applyForce( forcex, forcey, self.x, self.y ) &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;function drawExplosion(event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;circle = display.newCircle( event.x+20, event.y+20, 150 ) &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;circle.myName = "circle" &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;game:insert(circle) &nbsp; &nbsp; &nbsp; &nbsp; circle:setFillColor(100,100,100, 100) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; physics.addBody( circle, "static", {isSensor = true} ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; circle.collision = setExplosion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; circle:addEventListener( "collision", circle )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

    --Execute on bomb collision

&nbsp;&nbsp;&nbsp;&nbsp;function onCollision(event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:removeSelf() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:removeEventListener("touch", circleTouched) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:removeEventListener ( "collision", bomb ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hit = true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.performWithDelay ( 10, drawExplosion(event), 1 ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

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

&nbsp;&nbsp;&nbsp;&nbsp;--Shoot the bomb &nbsp;&nbsp;&nbsp;&nbsp;function circleTouched(event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if event.phase == "began" then&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display.getCurrentStage():setFocus(bomb) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif event.phase == "ended" then&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:applyLinearImpulse(event.xStart - event.x, event.yStart - event.y, bomb.x, bomb.y) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timer.performWithDelay ( 250, checkHit &nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display.getCurrentStage():setFocus(nil) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

And in case you want to see the rest of my code, here’s a link to my dropbox file: https://dl.dropbox.com/u/11212784/level_1.lua

I’m also open to alternatives to creating explosions, I tried Googling, but only managed to find a single tutorial regarding this on Tutsplus.

Hi @tomas,

Please try changing:

[lua]timer.performWithDelay ( 10, drawExplosion(event), 1 )[/lua]

to:

[lua]timer.performWithDelay ( 10, drawExplosion, 1 )[/lua]

It’s a subtle difference, but read point #1 in this FAQ:

http://www.coronalabs.com/blog/2012/08/15/faq-wednesday-display-object-listeners/

Brent

Managed to fix it, and everything seems to be working. Sort of.

My explosion still doesn’t do exactly what I want it to do. You mentioned something about an alternative?

Hi @tomas_buiting,
 
The one issue you mention is common and easily solved. As you see, certain things regarding physics collisions can’t be done while the system is “number crunching”. The solution is to trigger your action after an unnoticeable 10 millisecond timer, so the action occurs in the next “game cycle”:
 
[lua]
–in collision handler:

timer.performWithDelay( 10, explodeBomb, 1 )
[/lua]
 
As for your specific “bomb exploding” action, it might not give you the desired result to just set a big radial object to non-sensor. If the objects inside the sensor suddenly have to treat that object as “solid”, they might go flying off in all kinds of crazy, unbelievable force vectors. However, it’s worth a try. I might have a more comprehensive solution for you, but first try the above approach and see what happens.
 
Best regards,
Brent

Even with that miniature pause, I’m still getting that “error” I’m not quite sure why it’s still giving me that, since I remove the bomb from the stage before calling the explosion function.

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

As for my explosion, what I had in mind was this:

&nbsp;&nbsp;&nbsp;&nbsp;function setExplosion(self, event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local forcex = event.other.x-self.x &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local forcey = event.other.y-self.y-20 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(forcex \< 0) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 0-(80 + forcex)-12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 80 - forcex+12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.other:applyForce( forcex, forcey, self.x, self.y ) &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

Also, note that my radial object is actually set as a sensor, not a non-sensor.

Hi tomas,

It’s still giving you the “can’t do [something] while number crunching” error? That’s very odd. Can you post what your “drawExplosion()” function looks like and where it’s scoped in your  code? Is it above the “onCollision()” function as a local function?

Brent

All my code related to the explosion and collision:

&nbsp;&nbsp;&nbsp;&nbsp;function setExplosion(self, event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local forcex = event.other.x-self.x &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local forcey = event.other.y-self.y-20 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(forcex \< 0) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 0-(80 + forcex)-12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; forcex = 80 - forcex+12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.other:applyForce( forcex, forcey, self.x, self.y ) &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;function drawExplosion(event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;circle = display.newCircle( event.x+20, event.y+20, 150 ) &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;circle.myName = "circle" &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;game:insert(circle) &nbsp; &nbsp; &nbsp; &nbsp; circle:setFillColor(100,100,100, 100) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; physics.addBody( circle, "static", {isSensor = true} ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; circle.collision = setExplosion &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; circle:addEventListener( "collision", circle )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

    --Execute on bomb collision

&nbsp;&nbsp;&nbsp;&nbsp;function onCollision(event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:removeSelf() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:removeEventListener("touch", circleTouched) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:removeEventListener ( "collision", bomb ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hit = true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer.performWithDelay ( 10, drawExplosion(event), 1 ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

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

&nbsp;&nbsp;&nbsp;&nbsp;--Shoot the bomb &nbsp;&nbsp;&nbsp;&nbsp;function circleTouched(event) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if event.phase == "began" then&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display.getCurrentStage():setFocus(bomb) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif event.phase == "ended" then&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bomb:applyLinearImpulse(event.xStart - event.x, event.yStart - event.y, bomb.x, bomb.y) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timer.performWithDelay ( 250, checkHit &nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display.getCurrentStage():setFocus(nil) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;

And in case you want to see the rest of my code, here’s a link to my dropbox file: https://dl.dropbox.com/u/11212784/level_1.lua

I’m also open to alternatives to creating explosions, I tried Googling, but only managed to find a single tutorial regarding this on Tutsplus.

Hi @tomas,

Please try changing:

[lua]timer.performWithDelay ( 10, drawExplosion(event), 1 )[/lua]

to:

[lua]timer.performWithDelay ( 10, drawExplosion, 1 )[/lua]

It’s a subtle difference, but read point #1 in this FAQ:

http://www.coronalabs.com/blog/2012/08/15/faq-wednesday-display-object-listeners/

Brent

Managed to fix it, and everything seems to be working. Sort of.

My explosion still doesn’t do exactly what I want it to do. You mentioned something about an alternative?

Hi Tomas,

Sorry for the delay in response. Did you ever solve this? The alternative I was going to suggest was basically to create a radial sensor body (around the explosion center point). Then, for each object within its range, you apply an outward impulse based on how far that object is from the center, and in the correct direction.

For example, if the center point of the explosion was 0,0, and another object was at 100,-50, you’d apply a force of 100 and -50 to that object (factored down to the degree which seemed correct for the densities and how fast they blew outward). The same would be done to each object in the blast radius.

Would that do the trick?

Brent

Hi Tomas,

Sorry for the delay in response. Did you ever solve this? The alternative I was going to suggest was basically to create a radial sensor body (around the explosion center point). Then, for each object within its range, you apply an outward impulse based on how far that object is from the center, and in the correct direction.

For example, if the center point of the explosion was 0,0, and another object was at 100,-50, you’d apply a force of 100 and -50 to that object (factored down to the degree which seemed correct for the densities and how fast they blew outward). The same would be done to each object in the blast radius.

Would that do the trick?

Brent