Improvements for custom collision handling and impulse data

Topics: Developer Forum
Jun 18, 2012 at 12:17 PM

I started to use Farseer for a project that requires sophisticated handling of collisions and their impact energies a while ago. I was surprised to find out that both are quite hard to do in Farseer, which strikes me as odd, because it is all about collisions after all. Maybe i was missing something, but the only reliable way to get impulse data i found was the ContactManager.PostSolve, which is a very brute-force and ugly method.
The BreakableBody class is a great example of those shortcomings, which feels hack-ish at best with it's implementation requiring to have a BreakableBodyList stuffed into the World class and a PostSolve handler that scans through every single collision happening in the world.
And so i started to look for better solutions and made some changes that i'd like to share here in hopes that it may help someone else and might also be included in some future release.

First of all: PLEASE get rid of return values on event handlers! They are so aweful because only the LAST event subscriber can return a value. If you have multiple subscribers to a collision event then only the last subscriber is ever able to cancel the collision, which easily breaks your code! Use a reference argument instead like "void BeforeCollisionEventHandler(Fixture fixtureA, Fixture fixtureB, ref bool ignore)", allowing anyone of the subscribers to ignore the collision by setting ignore to true.

2) Add BeforeStep and AfterStep events to the World class, raised at the beginning and end of the Step method respectively (both having the "float dt" parameter). This allows objects to register for pre- and post-step calculations themselves, without requiring extra lists like BreakableBodyList that need to be managed by the user.

3) Add a ContactConstraint parameter to the AfterCollisionEventHandler, which allows to get very detailed collision data for the one fixture you actually need the data for, instead of having to check every single collision on PostSolve for appearances of this Fixture. Makes retrieval of data like per fixture impact impulse a LOT easier and is a huge performance optimization at the same time.

4) Add GetMaxImpulse() to ContactContraint class, as a convinient way to get the overall collision impulse. Works best in conjunction with the above suggestion.

      public float GetMaxImpulse() {
         float max = 0f;
         for (int i = 0; i < PointCount; i++) {
            if (Points[i].NormalImpulse > max) max = Points[i].NormalImpulse;
         return max;

5) Update BreakableBody to use the above improvements:
 - Add a private Variable to hold the max impulse to determine when to break. I named it "Stress".
 - Subscribe to the AfterCollision event of it's fixtures instead of the expensive world-wide PostSolve. Huge performance improvement!
 - In AfterCollision, use the new ContactConstraint.GetMaxImpulse() and store the result in "Stress" if the impulse is larger than its current value.
 - Subscribe to World.AfterStep and use it to check whether Stress is larger than Strength and break the object if it is. This also makes the BreakableBodyList in World entirely obsolete, which can be removed. Yay for simplicity!

I hope that'll help someone. Plase tell me if you find any flaws in my suggestions. They seem to work fine for me so far, though, and make the work with conditional and impact-power-aware collisions a lot easier.