Polygon collision is not working correctly

Topics: User Forum
Nov 8, 2013 at 9:07 PM
I have a problem with my polygon collision. In one special case, the collision isn't working properly. In this case, the ball touches both sides of the heart simultaneously and the ball isn't falling directly through the heart. The ball stops for a second and only after that it is falling through the heart. You can see that in this video: http://de.tinypic.com/r/zy8pw3/5
On the other hand, if the ball only touches one side of the heart, it's working correctly and the ball is falling directly through the heart. You can see that in this video: http://de.tinypic.com/r/2nujfv7/5

What is wrong with my code? Why is the polygon collsion not working correctly when the ball touches both sides of the heart simultaneously?
Is something wrong with my code or is that a bug in Farseer? I use Farseer 3.3.1.
public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        bool Draw_debugView = true;
        World world;
        Body Ball, Heart;
        Texture2D BallSprite, HeartSprite;
        List<Vertices> list = new List<Vertices>();
        Vector2 _origin;
        float _scale;

        DebugViewXNA physicsDebug;
        private Matrix _view;
        private Vector2 _cameraPosition;
        private Vector2 _screenCenter;

        private static float _displayUnitsToSimUnitsRatio = 100f;

        public static Vector2 ToDisplayUnits(Vector2 simUnits)
        {
            return simUnits * _displayUnitsToSimUnitsRatio;
        }

        public bool Heart_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            if (fixtureB.CollisionCategories == Category.Cat15)
                //remove the heart body if the ball touches it
              world.RemoveBody(fixtureA.Body);
            return true;
        }

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            TargetElapsedTime = TimeSpan.FromTicks(333333);
            InactiveSleepTime = TimeSpan.FromSeconds(1);
            graphics.IsFullScreen = true;
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            TouchPanel.EnabledGestures = GestureType.Tap;
            _view = Matrix.Identity;
            _cameraPosition = Vector2.Zero;
            _screenCenter = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2f, graphics.GraphicsDevice.Viewport.Height / 2f);
        
            if (world == null)
            {
                world = new World(new Vector2(0, 1));
            }
            else
            {
                world.Clear();
            }

            physicsDebug = new DebugViewXNA(world);
            physicsDebug.DefaultShapeColor = Color.White;
            physicsDebug.SleepingShapeColor = Color.LightGray;
            physicsDebug.LoadContent(GraphicsDevice, Content);

            BallSprite = Content.Load<Texture2D>("ballbig");
            HeartSprite = Content.Load<Texture2D>("heartbig");
            //create the ball
            Ball = BodyFactory.CreateCircle(world, 0.50f, 1.0f);
            Ball.BodyType = BodyType.Dynamic;
            Ball.Position = new Vector2(graphics.GraphicsDevice.Viewport.Width / 200f, graphics.GraphicsDevice.Viewport.Height / 200f-4f);
            Ball.Restitution = 0.5f;
            Ball.LinearVelocity = new Vector2(0, 2.0f);
            Ball.CollisionCategories = Category.Cat15;

            //create the heart
            uint[] data = new uint[HeartSprite.Width * HeartSprite.Height];
            HeartSprite.GetData(data);
            Vertices textureVertices = PolygonTools.CreatePolygon(data, HeartSprite.Width, false);
            Vector2 centroid = -textureVertices.GetCentroid();
            textureVertices.Translate(ref centroid);
            _origin = -centroid;
            textureVertices = SimplifyTools.ReduceByDistance(textureVertices, 4f);
            list = BayazitDecomposer.ConvexPartition(textureVertices);
            _scale = 1f;
            Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(1)) * _scale;
            foreach (Vertices vertices in list)
            {
                vertices.Scale(ref vertScale);
            }

            Heart = BodyFactory.CreateCompoundPolygon(world, list, 1.0f, BodyType.Static);
            Heart.IsSensor = true;
            Heart.Position = new Vector2(4.20f, 2.00f);
            Heart.Rotation = 0f;
            Heart.CollisionCategories = Category.Cat4;
            Heart.OnCollision += Heart_OnCollision;
        }

        protected override void Update(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            world.Step(Math.Min(elapsed, (1f / 60f)));

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();
              spriteBatch.Draw(BallSprite, ConvertUnits.ToDisplayUnits(Ball.Position), null, Color.White, Ball.Rotation, new Vector2(BallSprite.Width / 2.0f, BallSprite.Height / 2.0f), 1f, SpriteEffects.None, 0f);
              spriteBatch.Draw(HeartSprite, ConvertUnits.ToDisplayUnits(Heart.Position), null, Color.White, Heart.Rotation, _origin, _scale, SpriteEffects.None, 0f);          
            spriteBatch.End();

            if (Draw_debugView == true)
            {
              Matrix projection = Matrix.CreateOrthographicOffCenter(0f, graphics.GraphicsDevice.Viewport.Width / _displayUnitsToSimUnitsRatio, graphics.GraphicsDevice.Viewport.Height / _displayUnitsToSimUnitsRatio, 0f, 0f, 1f);
              Matrix view = Matrix.CreateTranslation(new Vector3((_cameraPosition / _displayUnitsToSimUnitsRatio) - (_screenCenter / _displayUnitsToSimUnitsRatio), 0f)) * Matrix.CreateTranslation(new Vector3((_screenCenter / _displayUnitsToSimUnitsRatio), 0f));
              physicsDebug.RenderDebugData(ref projection, ref view);
            }

            base.Draw(gameTime);
        }
    }
Nov 17, 2013 at 10:38 AM
The problem was solved in this thread: http://farseerphysics.codeplex.com/discussions/468497