Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OnCollision event handler problems in C# XNA with Farseer Physics

Tags:

c#

xna

farseer

I have this working ok(ish) in my game at the moment, but i'm not fantastic at maths. When two primatives collide, I want them to smash up into tiny bits if the force applied to a primative was over a set threshold. My collision event handler at present looks like this.

public bool Collision(Fixture fixtureA, Fixture fixtureB, Manifold manifold) 
{ 
   Vector2 position = manifold.LocalNormal; 
   float angle = (float)Math.Atan2(position.Y, position.X); 
   Vector2 force = Vector2.Zero; 
   if (angle < 0) 
     force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi + angle) * fixtureA.Body.LinearVelocity.Y); 
   else 
     force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi - angle) * fixtureA.Body.LinearVelocity.Y); 
   double XForce = Math.Sqrt(force.X * force.X); 
   double YForce = Math.Sqrt(force.Y * force.Y); 
   double totalForce = XForce + YForce; 
   if ((Breakable) && (totalForce > BreakForce)) 
   { 
      Breakable = false; 
      Active = false; 
      BreakUp(fixtureA, fixtureB); 
   } 
   return true; 
} 

I put that in a LONG time ago when I was just playing around. This causes a bit of a problem in certain situations. For example, if a primative is stationary on the floor and another primative falls onto it from a decent height, almost always, the falling box blows up and the resting box survives. Also if two boxes are falling side by side and give each other the tinyest of touches, then both boxes blow up mid air. Hmmmmm, not really perfect that. Does anyone have any idea how to improve my collision handler? Thanks in advance.

like image 731
DrLazer Avatar asked Jul 22 '10 10:07

DrLazer


2 Answers

Ok, so my other answer is viable. But I've looked at Farseer 3.0 (the current SVN version) more closely and found that it already implements almost exactly what you are trying to do.

Look for "BreakableBody.cs". You may be able to directly use that - but otherwise you could just copy out the functionality you want.

Specifically: Instead of attaching a function to your fixture's OnCollision you want to attach one to PostSolve. It takes a ContactConstraint which you can dive into and find the impulses from the collision.

This is the implementation of that function used by BreakableBody:

private void PostSolve(ContactConstraint contactConstraint)
{
    if (!Broken)
    {
        float maxImpulse = 0.0f;
        for (int i = 0; i < contactConstraint.manifold.PointCount; ++i)
        {
            maxImpulse = Math.Max(maxImpulse,
                         contactConstraint.manifold.Points[0].NormalImpulse);
            maxImpulse = Math.Max(maxImpulse,
                         contactConstraint.manifold.Points[1].NormalImpulse);
        }

        if (maxImpulse > Strength)
        {
            // Flag the body for breaking.
            _break = true;
        }
    }
}

Apparently the impulse data in the manifolds is only set correctly in PostSolve, not in OnCollision.

like image 86
Andrew Russell Avatar answered Oct 20 '22 06:10

Andrew Russell


I haven't used XNA, but as a physics problem, why not just subtract the linear velocity of A from the linear velocity of B, and get the 'force' as the square of the resulting vector (sum the squares of the components)? That should harmonize with the kinetic energy involved according to `E=(mv^2)/2', for a very simple physical model, even if we are ignoring the masses (or, for that matter, elasticity or the distinction between energy and momentum). If the objects are moving in the same general direction at the same speed, you get a small value; if one is approaching (or, of course, departing!) at high speed, you get a large value.

like image 30
Pontus Gagge Avatar answered Oct 20 '22 05:10

Pontus Gagge