0
\$\begingroup\$

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:

pre-collision, 1 bullet post-collision, 1 bullet

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.

pre-collision, 3 bullets post-collision, 3 bullets

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.

\$\endgroup\$
1
\$\begingroup\$

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

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 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... \$\endgroup\$ – mpl Sep 6 '13 at 0:29
  • \$\begingroup\$ 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. \$\endgroup\$ – Chachmu Sep 9 '13 at 14:58
1
\$\begingroup\$

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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 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? \$\endgroup\$ – mpl Sep 6 '13 at 19:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.