OnCollision w\ multiple contacts => Dispose body

Jan 12, 2011 at 5:22 PM
Edited Jan 12, 2011 at 8:42 PM

Hi!

I would like to dispose a fixture in it's own OnCollision.

The problem is: if I have multiple contacts and because of that I cannot dispose the body without getting Error in the next OnCollision (that happens in the same moment because of multiple contacts on multiple different fixtures).

I have tried to use    if (contact.next == null) body.dispose;    I thought that means: if there is not another contact then there is not another OnCollision and I could dispose the body because it isn't needed anymore.

But the problem is that sometimes I get:

contect.prev != null and
contact.next == null and I do not get another OnCollision.

Or sometimes I even get contact.prev == something and contact.next == something, although I have only 2 bodies which are in collision with the OnCollision's body.

I hope you understand what I mean xD


Just to be sure:

I have one bullet which hits two Enemies at the same time and I need to dispose it properly without getting an error in the second OnCollision.

Thank you very much!

 

EDIT:
K, I have have managed to do it with  (bullet.UserData as Bullet).Fixture.Dispose(); at the end and    if (bullet == null) return false; at the beginning, so if a bullet hits two enemies at the same time it get's disposed at the first enemy's OnCollision, and the second one's OnCollision doesn't do anything =D
I thought there was maybe a better way for this to handle both enemies and dispose after the last one, but for now it's ok.. although I would still appreciate a hint =D

Good night ; )

Jan 14, 2011 at 9:33 AM

Hi! I am still having this problem and I can't find the reason.

If my bullet colides with multiple enemies, OnCollision gets fired multiple times.

In OnCollision I am disposing the bullet fixture, and I then get an error at removeBody (but only if the bullet hits 2 or more enemies, one enemyhit is ok).

When I look into the BodyRemoveList I can see that the body is already there - which for me seems like OnCollision gets fired a second time but the body is already in BodyRemoveList.

Can you help me out without seeing my code?

Thank you! (for your great engine!)

Developer
Jan 14, 2011 at 10:02 AM

Hi,

During a timestep (and thus during OnCollision) it is not a good idea to remove fixtures or bodies as they are currently processed by Farseer. As of 3.2 you can however do that, because Farseer caches all those request automatically and removes the bodies/fixtures before the next timestep.

Therefore it is really evil to use something like Fixture.Dispose(). If you just want to remove a fixture use Body.RemoveFixture(). If you want to get rid of a complete body (with everything thats attached to it) use World.RemoveBody().

As the objects are cached and removed later, you can get multiple OnCollision events. Farseer won't remove anything more than once, but has an assertion built in if you try that because it might be unintentional and an error in your code.

One clean solution would be: Set the UserData of your bullet to something like "marked for removal" in the first OnCollision event and remove it with World.RemoveBody(). Check the UserData in OnCollsion and if an object is already "marked for removal" cancel the collision and do nothing else.

@genbox: Would it be worthwhile to have a switch like "report duplicate removal" within settings.cs and maybe return true/false when calling RemoveBody() as it might be handy not to have the current Debug.Assert in place in many situations, even though it just fires in Debug mode?

Mar 12, 2014 at 3:07 PM
Oh, it is a really old post, but still I want to add my solution:

In onCollision method after you call world.RemoveBody(Body); call Body.CollidesWith = Category.None;
So it will no longer collide with other bodies.

I had this problem when two or more same size body were overlapped and bullet hit them.
By using this solution bullet hit just one of them(don't know how it find which one to hit, but other bullets hits the same body, and after that body been removed next bullet hit another body).