# How to cancel out simultaneous collisions in libGosu?

I am working on an Asteroids remake. When the player's bullets hit a large meteor, it should break apart into 2 smaller meteors. This works when the player is only firing one bullet, but when the player's weapon is upgraded, shooting multiple bullets, sometimes two bullets hit the same meteor at the same time, causing it to break into 4 smaller meteors, not 2 as intended.

Is there a way to cancel out one of the collisions when there are two simultaneous collisions - or a way to omit the creation of the unwanted extra meteors when two bullets hit the same meteor at the same time?

Here is how I have the collision detection set up currently:

Bullet.each_collision(Meteor1) do |bullet, meteor|
Explosion.create(:x => meteor.x, :y => meteor.y)
Meteor2.create(:x => meteor.x, :y => meteor.y)
Meteor2.create(:x => meteor.x, :y => meteor.y)
meteor.destroy
bullet.destroy
@score += 100
Sound["media/audio/explosion.ogg"].play(0.2)
end


Following are screenshots demonstrating the situation:

In the first two images (above) the player fires one bullet at a time, the large meteor breaks into two smaller meteors, and the score increases by 100.

In the last two images, the player fires three bullets at a time, the large meteor breaks apart into four smaller meteors, and the score increases by 200, due to a simultaneous collision.

Just add a small delay that keeps the meteors from splitting apart for an instant after it has just been split.

• Just adding a small delay sounds like such a simple task, and yet I have been wracking my brain about how to accomplish this. One of the guys from the LibGosu forums recommended that I use break, which seems to be working. I assume that this has the effect of a small delay... – mpl Sep 6 '13 at 0:29
• I have never used LibGosu but if you have a game loop running you can just set a variable Delay, then implement it each frame until you get the desired time. Or, just save the time that it happened, then check if enough time has passed since then. – Chachmu Sep 9 '13 at 14:58

You need to ensure that the block is ignored if the meteor has already been destroyed:

require 'set'

destroyed_meteors = Set.new
Bullet.each_collision(Meteor1) do |bullet, meteor|
# Prevent multiple destructions of a single meteor
next if destroyed_meteors.include? meteor
destroyed_meteors << meteor

Explosion.create(:x => meteor.x, :y => meteor.y)
Meteor2.create(:x => meteor.x, :y => meteor.y)
Meteor2.create(:x => meteor.x, :y => meteor.y)
meteor.destroy
bullet.destroy
@score += 100
Sound["media/audio/explosion.ogg"].play(0.2)
end

• I'm attempting to try this out, but I'm having difficulties with require 'set'. Is this a class which I should create myself? What should it look like? – mpl Sep 6 '13 at 19:01