Page 1 of 2

Double collision detection

Posted: Mon Oct 29, 2012 8:42 pm
by ucode
I'm using the Ruby port of chipmunk and detect collisions with:

Code: Select all

    @space.add_collision_func(:bullet, :player) do |bullet, player_hit|
      @sound.play
      @player.reset_position
    end
Problem is the block of code gets executed twice whenever there's a collision. I move the player far away, so it's not like the collision happens again because the player is still right next to the bullet.

What's happening and how do I prevent this?

Re: Double collision detection

Posted: Mon Oct 29, 2012 9:59 pm
by slembcke
Hmm. I assume #add_collision_func is a compatibility function that wraps the now very old Chipmunk API function of the same name. The way that worked is that it would call the callback for every frame that things are overlapping. Without seeing more code (yours and the binding), I can't say either way if this was happening or not.

There should be something that wraps the much newer collision handler functionality (cpSpaceAddCollisionHandler()) which lets you register separate begin, preSolve, postSolve, and separate callbacks. Begin callbacks are guaranteed to be called only once.

Re: Double collision detection

Posted: Tue Oct 30, 2012 3:58 pm
by ucode
slembcke wrote:Hmm. I assume #add_collision_func is a compatibility function that wraps the now very old Chipmunk API function of the same name. The way that worked is that it would call the callback for every frame that things are overlapping. Without seeing more code (yours and the binding), I can't say either way if this was happening or not.

There should be something that wraps the much newer collision handler functionality (cpSpaceAddCollisionHandler()) which lets you register separate begin, preSolve, postSolve, and separate callbacks. Begin callbacks are guaranteed to be called only once.
Looks like there is an add collision handler method (http://beoran.github.com/chipmunk/#Callbacks), trying it now. Thanks.

Re: Double collision detection

Posted: Tue Oct 30, 2012 5:13 pm
by ucode
ucode wrote:Looks like there is an add collision handler method (http://beoran.github.com/chipmunk/#Callbacks), trying it now. Thanks.
Unfortunately, the following code also calls the collision handler twice for every collision :(.

Code: Select all

@space.add_collision_handler(:floor, :player, CollisionHandler.new(@player))
class CollisionHandler
  def initialize(player)
    @player = player
  end
  def begin(a, b, arbiter)
    puts "collided first? #{arbiter.first_contact?}"
    @player.reset_position
  end
end
On every collision I get the following output:

Code: Select all

first contact? true
first contact? true

Re: Double collision detection

Posted: Tue Oct 30, 2012 5:17 pm
by slembcke
Do you have multiple shapes on your object? Contacts are tracked per pair of shapes. If you have a composite object, you need to increment a counter on begin and decrement it on separate. When you go from 0 -> 1 you know it's the first contact, and when you go from 1 -> 0 you know it's the final contact separating.

Re: Double collision detection

Posted: Tue Oct 30, 2012 5:45 pm
by ucode
slembcke wrote:Do you have multiple shapes on your object? Contacts are tracked per pair of shapes. If you have a composite object, you need to increment a counter on begin and decrement it on separate. When you go from 0 -> 1 you know it's the first contact, and when you go from 1 -> 0 you know it's the final contact separating.
wouldn't first_contact? be false if it wasn't the first contact? The player is a simple Circle shape and the floor is a Segment.

Re: Double collision detection

Posted: Tue Oct 30, 2012 6:10 pm
by slembcke
Hmm. Single shape on each object should only produce one callback yeah. Also you don't need to check if it's the first contact in a begin callback. That will always be true.

You should try printing out the shapes on the arbiter to check that it's not the same pair of objects. Also implement the separate callback event to log something as well so you know that isn't happening in between unexpectedly. Is it possible that the object is bouncing?

Re: Double collision detection

Posted: Tue Oct 30, 2012 7:52 pm
by ucode
slembcke wrote:Hmm. Single shape on each object should only produce one callback yeah. Also you don't need to check if it's the first contact in a begin callback. That will always be true.

You should try printing out the shapes on the arbiter to check that it's not the same pair of objects. Also implement the separate callback event to log something as well so you know that isn't happening in between unexpectedly. Is it possible that the object is bouncing?
It shouldn't be possible that the object is bouncing because @player.reset_position moves the player away from the floor.

Re: Double collision detection

Posted: Tue Oct 30, 2012 8:05 pm
by ucode
ucode wrote:It shouldn't be possible that the object is bouncing because @player.reset_position moves the player away from the floor.
I guess this is part of the issue. In the reset_position method I'm moving the player with:

Code: Select all

@player.shape.body.p.x = 50  # which is far from the other object
That does move my player as expected, but I guess that's also causing my collision callback to be called again. If I remove that resetting of the position, then my callback is called many times but only in the first time is arbiter.first_contact? equal to true.

Re: Double collision detection

Posted: Wed Oct 31, 2012 6:17 am
by ucode
So how can I move my player away from the other object when a collision occurs without my collision handler being called twice?