Having trouble with Corona Collision Detection

Hello guys I am back. I hope you will help me again this time.

This time I am having trouble with collision detection. Here is my code:

function collisionHandler(e) if(e.other.name == 'bullet' and e.target.name == 'enemy') then --it works with this line -- audio.play(explo) -- timer.cancel(enemyFire) -- enemyFire=nil -- print(enemyFire) display.remove(e.other) display.remove(e.target) e.target=nil elseif(e.other.name == 'eBlaster' and e.target.name == 'ship') then --but does not with this line -- audio.play(explo) -- timer.cancel(enemyFire) -- enemyFire=nil -- print(enemyFire) display.remove(e.other) display.remove(e.target) e.target=nil end end

Here is the code for eBlaster:

local function fire() if enemy == nil or enemy.removeSelf == nil then return true end local function shoot() local blaster = display.newImageRect( "images/ammoE.png", 20, 20 ) blaster.x = enemy.x blaster.y = enemy.y+5 blaster.name='eBlaster' physics.addBody(blaster, "kinematic"); -- blaster.bodyType='static' transition.to( blaster, { time=5000, y=(screenH+100),transition=easing.outSine} ) sceneGroup:insert(blaster) blaster:addEventListener('collision',collisionHandler)

And here is the code for the ship:

local function createShip( ) --ship creation ship = display.newImageRect ("images/ship.png",100,50) ship.x = display.contentWidth/2 ship.y = display.contentHeight-10 ship.name = 'ship' ship:addEventListener('collision', collisionHandler) physics.addBody(ship, "dynamic", {density = 1, friction = 0, bounce = 0});

What I want to happen is upon contact with enemy fire (‘eBlaster’) my ship will explode. But its not even detecting collision. I tried adding (“Collision Detected!”) to my collisionHandler to check if there is collision but it still does not work. Also I am working with composer and eBlaster is above 

function scene:create( event )

while ship is within it. Can somebody please help?

Don’t know if this will help at all, but this is how I handle things.

When setting up your objects (player ship, enemies etc.) 

ship.collision=collisionHandler -- add this line ship:addEventListener('collision', ship) -- alter this one to whichever object you're creating

Rename (temporarily) your current collision handler, then try this…

local function collisionHandler ( self, event ) print (self.name, event.other.name) -- You can see what is colliding with what for debugging -- You can add in the rest of your collision stuff here end

I know it’s only a slight difference from the way you’ve done things but for some reason I find it easier.

Hope this helps in some way.

First of all thank you for the reply. I tried both of your codes but it seems it still won’t work. Also ship and eBlaster reports no collision at all with print (self.name, event.other.name). I tried doing some more tests and I found out that it was ship that is not detecting any collisions. Is there another way to handle this?

Kinematic objects do not generate collision events. 

I never knew that.  But then I’ve never used Kinematic bodies before.

Kinematic objects do not generate collision events. You could make it “dynamic” and set .isSensor to true and that will generate collisions.  If you don’t want gravity affecting your entire game, you can turn it off for the whole world, or if you want gravity off for a specific object then you can set the object’s gravityScale to 0. See: https://docs.coronalabs.com/api/type/Body/gravityScale.html

It’s okay to use transitions to move physics objects as long as the physics isn’t trying to move the object at the same time your non-physics method is. Pick one or the other but not both. 

You can look at the code for the Getting Started guide as a reference: https://docs.coronalabs.com/guide/programming/index.html

Rob

I thought kinematic bodies collide with dynamic bodies? I didn’t know that they don’t generate collision events. Also my code for player blaster (pBlaster) uses kinematic bodies and it works well. It collides with enemy that uses dynamic bodies.

I tried changing for ship into 

ship = display.newImageRect ("images/ship.png",100,50) ship.x = display.contentWidth/2 ship.y = display.contentHeight-10 ship.name = 'ship' ship.collision=collisionHandler ship:addEventListener('collision', ship) physics.addBody(ship, "dynamic", {density = 1, friction = 0, bounce = 0}); ship.isSensor=true

and eBlaster into 

local blaster = display.newImageRect( "images/ammoE.png", 20, 20 ) blaster.x = enemy.x blaster.y = enemy.y+5 blaster.name='eBlaster' physics.addBody(blaster, "dynamic"); blaster.isSensor=true transition.to( blaster, { time=5000, y=(screenH+100),transition=easing.outSine} ) blaster.collisionHandler=collisionHandler blaster:addEventListener('collision',blaster)

but it still not working. Do you have any other tips?

kinematic bodies do collide with dynamic bodies, and they do generate collision events.  what they don’t do is have any collision response - a kinematic body has essentially infinite mass, so no amount of force is ever going to budge it, so collision response is a non-starter.  (a dynamic body colliding with a kinematic body will have a response though)

Kinematic bodies absolutely cause collision events, so please ignore the response above.

I believe the minor confusion was this: to generate a collision event, at least ONE of the bodies must be dynamic. So the following combinations are valid:

  • dynamic + dynamic
  • dynamic + static
  • dynamic + kinematic

And the following combinations are NOT valid (will not generate a collision response):

  • kinematic + kinematic
  • static + static
  • static + kinematic

@kurokawashinji47, as for your code, I believe this is the problem:

This line is incorrect:

[lua]

blaster.collisionHandler=collisionHandler

[/lua]

It should be this:

[lua]

blaster.collision=collisionHandler

[/lua]

Basically, what you’re telling Corona here is that the “blaster” object should honor “collision” events (there are other types like “preCollision” and “postCollision”, so that’s why you must specify this parameter). Then, you’re telling Corona that the event listener function for those collision events should be “collisionHandler”.

Hope this helps,

Brent

I see my mistake. Yes, please ignore my stupidity. Brent is right. I misread the code I was testing and one of the objects was static, not dynamic like I thought.

Mea Culpa.

Rob

Thanks for correcting my code.

Now that I’ve changed it into 

blaster.collision=collisionHandler blaster:addEventListener('collision',blaster)

but it’s throwing me a runtime error so I tried changing it into

blaster:addEventListener('collision', collisionHandler)

then runtime error disappeared but still no collision detection. Is there any difference between the two? And which do you think is better to use?

you may want to read this with regard to what Appletreeman said above - you may be mixing and matching local/global listener styles. (fe, “e.other” looks local, but your handler lacks a “self” parameter which looks global) 

In some cases where most of your collision are based on one object it pays to have a local collision listener. For instance, a ping pong game:

All collisions will have the ball as one of the objects, but for a space shooter, you need to detect when asteroids and lasers collide or asteroids with other asteroids etc.

I do see that the ship is dynamic and the bullet is kinematic, so I am not sure why you are having trouble. 

You are probably getting a runtime error because of scope. You created a local variable within a function so it will not be accessible anywhere else. Try putting:

local blaster

At the top of your file, then when you are setting its position and adding its physics body, simply remove ‘local blaster’ and just put ‘blaster’.

Hi again,

What is the runtime error you’re getting? That would help us diagnose.

Also, please just remove the second parameter of the :addEventListener() call entirely (my fault for not mentioning that in my last response). So, change your code to just:

[lua]

blaster.collision = collisionHandler

blaster:addEventListener(‘collision’)

[/lua]

Basically, the former way (repeating the object reference as the second parameter) was a redundant thing that was deprecated long ago. It’s not necessary to include any second parameter when using “local” collision handling.

Brent

Thank you very much for taking your time to help me. The error says:

stage1.lua:262 attempt to index field ‘other’ ( a nil value) stack traceback:

          stage1.lua:262 in function <stage1.lua:261>

          ?: in function <?:169>

Should I include my code as well?

Please include that code.

Hello everyone. First of all thank you for taking the time to answer my questions. I seem to have found a way to fix my problem. I tried adding a physics.setDrawMode( “hybrid” ) to my code and noticed that my ship is not generating a physics body unlike my enemies. So I tried changing my code for ship to mimic the code for my enemy and put it in a timer and it created a physical body. Collision works well now.

Don’t know if this will help at all, but this is how I handle things.

When setting up your objects (player ship, enemies etc.) 

ship.collision=collisionHandler -- add this line ship:addEventListener('collision', ship) -- alter this one to whichever object you're creating

Rename (temporarily) your current collision handler, then try this…

local function collisionHandler ( self, event ) print (self.name, event.other.name) -- You can see what is colliding with what for debugging -- You can add in the rest of your collision stuff here end

I know it’s only a slight difference from the way you’ve done things but for some reason I find it easier.

Hope this helps in some way.

First of all thank you for the reply. I tried both of your codes but it seems it still won’t work. Also ship and eBlaster reports no collision at all with print (self.name, event.other.name). I tried doing some more tests and I found out that it was ship that is not detecting any collisions. Is there another way to handle this?

Kinematic objects do not generate collision events. 

I never knew that.  But then I’ve never used Kinematic bodies before.