Circle -> Edge collision results in circle stuck to wall

Topics: User Forum
Dec 1, 2010 at 4:22 AM

I'm working on a simple game using Farseer but have hit this critical bug. From a physics standpoint my game consists of a number of circles bouncing around inside of a screen-sized box. The circles have no linear damping, no friction, 1 for restitution, and have IsBullet set to true to avoid going through any walls. There is no gravity. I create four static walls around the world using the FixtureFactory (and then setting the BodyType to Static and IsStatic to true) and then some number of other edges inside this world for obstacles. This creates a box  with circles that bounce around indefinitely which is what I want. The world itself is in the range of (0,0) to (24, 40).

However I've noticed that sometimes a circle will hit a wall and instead of bouncing will just get stuck to it. It may still move along the surface of the wall, but it should have bounced away from the wall. I've seen this happen quite frequently, enough so that it's going to make my game not really work until solved.

Has anyone else seen this behavior? Anyone have any ideas what the root cause could be and how I could solve it?

Coordinator
Dec 1, 2010 at 4:44 AM

What version of FPE are you using? Are the walls edge shapes or polygon shapes?

Dec 1, 2010 at 4:59 AM

I'm using 3.1. I believe they are just edges; I create them like this:

var f = FixtureFactory.CreateEdge(world, start, end, 10f);
f.Body.IsStatic = true;
f.Body.BodyType = BodyType.Static;
f.Friction = 0f;

Developer
Dec 1, 2010 at 1:09 PM

Not really sure, but this could happen upon hitting multiple edges at the same time. Do you have colinear edge shapes in your setup? If so... are you using the adjacency information of the edge shapes as e.g. the loop shape does? Also it might be worthwhile to try switching off continous collision detection in the farseer settings, if your objects aren't moving to fast.

Dec 1, 2010 at 3:59 PM
Edited Dec 1, 2010 at 4:04 PM

No colinear shapes going on here; all edges are unique. I'll try turning off continuous collision detection and seeing if that works for me. Hopefully it doesn't lead to the circles managing to get through the walls, but we'll see if it has any effect on them getting stuck.

EDIT: Tried it out with no CCD and it didn't seem to fix things. I've also noticed that sometimes two circles will collide and one seems to "steal" all of the momentum leaving the other one nearly stopped. Is that also normal given that all circles are the same mass? I had assumed that two circles both moving would decent velocity would still have decent velocity after a collision as well.

Coordinator
Dec 1, 2010 at 8:39 PM

If two circles collide (perfect collision - head on) with the same mass and same velocity; they will both stop. However, it sounds like there is a bug somewhere - CCD should prevent your circle from sticking with anything as tunneling is reduced to next to nothing.

Can you recreate this in a Testbed (download the Testbed from the download tab) sample? It might be a bug in the Box2D code.

Dec 2, 2010 at 11:56 AM

I have an identical problem, where a sphere is thrown against a tilted box - most spheres bounce but quite a few start slowly following the edge of the box - even beyond the box. I'll see if I can create a minimal demo.

Dec 2, 2010 at 5:51 PM

Here's an example that demonstrates the problem, it bounces a stream of particles against a box. Every few particles hugs the side of the box instead of bouncing away from it.

public class WallHuggingExample : Test
    {
        private Random _random = new Random();
        private List<Fixture> _particles = new List<Fixture>();

        private WallHuggingExample()
        {
            World.Gravity = new Vector2(0, 0);
            Fixture rectangle = FixtureFactory.CreateRectangle(World, 15, 15, 1);
            rectangle.Body.Rotation = 0.3f;
            rectangle.Body.Position = new Vector2(18, 18);
            rectangle.Body.IsStatic = true;
            rectangle.Body.BodyType = BodyType.Static;
            rectangle.Restitution = 1;
        }

        internal static Test Create()
        {
            return new WallHuggingExample();
        }

        public override void Update(GameSettings settings, GameTime gameTime)
        {
            base.Update(settings, gameTime);

            Fixture circle = GenerateParticle();
            while (_particles.Count() > 300)
            {
                World.RemoveBody(_particles.First().Body);
                _particles.RemoveAt(0);
            }
        }

        private Fixture GenerateParticle()
        {
            Vector2 dir = new Vector2(1, 1);
            dir.Normalize();
            Vector2 pos = new Vector2(1, 1);

            // Random position
            float angle = (float)(_random.NextDouble() * 2 * Math.PI);
            float radius = (float)(_random.NextDouble() * 0.05);
            Vector2 position =
                new Vector2(
                    (float)(pos.X + (Math.Cos(angle) * radius)),
                    (float)(pos.Y + (Math.Sin(angle) * radius)));

            float speed = (float)20;
            Vector2 linearVelocity = Vector2.Multiply(dir, speed);
            Fixture circle = FixtureFactory.CreateCircle(World, 0.5f, 1);
            circle.Body.IsStatic = false;
            circle.Body.LinearVelocity = linearVelocity;
            circle.Body.Position = position;
            circle.Restitution = 1;
            circle.CollisionCategories = CollisionCategory.Cat31;
            circle.CollidesWith = CollisionCategory.All & ~CollisionCategory.Cat31;
            _particles.Add(circle);

            return circle;
        }
    }

Dec 6, 2010 at 9:34 PM
Edited Dec 6, 2010 at 9:35 PM

I have the same problem in my game and I did some little research.

Basing on mfagerlund example, when we set Settings.VelocityThreshold value below -20.0 the problem disappear.
In file ContactSolver.cs, method InitializeVelocityConstraints() when vRel is calculating, sometimes we get positive value so collision is treat as inelastic and ball sticks to wall.

// Setup a velocity bias for restitution.
ccp.VelocityBias = 0.0f;
float vRel = Vector2.Dot(cc.Normal, vB + new Vector2(-wB * ccp.rB.Y, wB * ccp.rB.X) - vA - new Vector2(-wA * ccp.rA.Y, wA * ccp.rA.X));

if (vRel < -Settings.VelocityThreshold)
{
ccp.VelocityBias = -cc.Restitution * vRel;
}

I temporary "fix" it by adding

vRel = -Math.Abs(vRel);

but this need a proper bugfix :-)

InitializeVelocityConstraints()
Coordinator
Dec 6, 2010 at 10:14 PM

That hack can introduce some pretty weird physics related to restitution. The bug is inside the CCD system as disabling it will produce the correct behavior.

Coordinator
Dec 6, 2010 at 11:15 PM

I've fixed the bug. Warm starting was used in the CCD solver - we don't need warm starting in there and as a result it would create incorrect collision results. The bug fix is in the latest change-set (81565).

Dec 8, 2010 at 8:00 PM

 

Great!

Coordinator
Dec 8, 2010 at 8:53 PM

Let me know if you still have problems with the balls. I might have fixed that one bug, but I found another one in the process of fixing it, and it lets me to believe that there might be more

Dec 8, 2010 at 8:53 PM

Will do!

Från: Genbox [mailto:notifications@codeplex.com]
Skickat: den 8 december 2010 22:53
Till: Mattias Fagerlund
Ämne: Re: Circle -> Edge collision results in circle stuck to wall [FarseerPhysics:236640]

From: Genbox

Let me know if you still have problems with the balls. I might have fixed that one bug, but I found another one in the process of fixing it, and it lets me to believe that there might be more

Read the full discussion online.

To add a post to this discussion, reply to this email (FarseerPhysics@discussions.codeplex.com@discussions.codeplex.com)

To start a new discussion for this project, email FarseerPhysics@discussions.codeplex.com@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Coordinator
Dec 8, 2010 at 8:58 PM

Oh, and just to let you know. I hope it is okay that I posted your game on Facebook. I have quite a lot of friends that love the game and it is only about 10 minutes ago I passed by one of them sitting there playing level 18. Keep up the good work.

Dec 8, 2010 at 8:59 PM

Thanks, that’s great to hear!

Cheers,

mattias

Från: Genbox [mailto:notifications@codeplex.com]
Skickat: den 8 december 2010 22:58
Till: Mattias Fagerlund
Ämne: Re: Circle -> Edge collision results in circle stuck to wall [FarseerPhysics:236640]

From: Genbox

Oh, and just to let you know. I hope it is okay that I posted your game on Facebook. I have quite a lot of friends that love the game and it is only about 10 minutes ago I passed by one of them sitting there playing level 18. Keep up the good work.

Read the full discussion online.

To add a post to this discussion, reply to this email (FarseerPhysics@discussions.codeplex.com@discussions.codeplex.com)

To start a new discussion for this project, email FarseerPhysics@discussions.codeplex.com@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Dec 10, 2010 at 5:06 AM

I'm still seeing this issue with the latest Farseer source. I didn't change any of my application code (other than to fix the compilation error with FixtureFactory.CreateEdge that changed at some point). I've tried turning off the CCD, but I still see the bug regardless of whether or not the CCD is turned on (I'm toggling it in the Settings.cs).

Coordinator
Dec 10, 2010 at 1:18 PM

Be sure that you are running with the latest version of Farseer Physics Engine and be sure that you are not referencing a stale DLL. (Clean your bin folders to be sure)

If the problem is still in there, I would really appreciate it if you could create a small testbed test (using the official Testbed project) that reproduces the error.

Mar 17, 2011 at 4:12 PM

I'm having the same problem here: the circle just get stuck to the wall. I'm using the latest version of Farseer. Has anybody solved this problem?

Apr 3, 2011 at 11:28 AM

I'm having the same problem as well.  The circles don't get stuck, but they hug the wall when they hit.  I have Farseer 3.3.

Apr 4, 2011 at 2:50 AM

I have this problem as well. Reducing my game units to simulation units ratio from 100 to something smaller like 20 has seemingly made it go away.

Developer
Apr 4, 2011 at 8:57 AM

@DualOpAmp: Assuming you scaled your Physics world accordingly etc. etc. I would further assume that you are not encountering a bug but the expected behavior. If you want the circle to bounce of the wall, try setting its restitution to a higher value. Have a look at the restitution sample within the samples framework.

Apr 11, 2011 at 10:08 PM

I set the simulation units down to 24.  And all my objects have a restitution of 1.0.  Yet, I still have the problem.

Developer
Apr 12, 2011 at 8:45 AM

You mean one sim unit equals 24 pixels? How big are your objects, how much mass do they have, how big are the forces you are using and is everything looking alright in the DebugView?

Apr 12, 2011 at 10:57 AM
Edited Apr 12, 2011 at 11:00 AM
From the game class:
// Scale the whole thing smaller.
            ConvertUnits.SetDisplayUnitToSimUnitRatio(24f);

From the bar class:
this.hitBox = FixtureFactory.AttachRectangle(ConvertUnits.ToSimUnits(200), ConvertUnits.ToSimUnits(10), 1,
                Vector2.Zero, BodyFactory.CreateBody(this.myWorld), "bar");
            this.hitBox.Restitution = 1.0f;

this.hitBox.Restitution = 1.0f;

From the Level Class: 

 

 

this.balls = new List();
            this.balls.Add(FixtureFactory.AttachCircle(ConvertUnits.ToSimUnits(7), 1f, BodyFactory.CreateBody(this.physWorld),
                new BallData(Vector2.Zero, "ball")));
            this.balls[0].Body.BodyType = BodyType.Dynamic;
            this.balls[0].Restitution = 1.0f;
            this.balls[0].Friction = 0.0f;
            this.balls[0].OnCollision += new OnCollisionEventHandler(this.BallCollision);
            this.balls[0].AfterCollision += new AfterCollisionEventHandler(this.AfterCollision);
            this.ResetBall();

 

Developer
Apr 12, 2011 at 11:59 AM

This looks okay so far. Could you try to reproduce the balls behavior in our testbed and send me the sample? 

Apr 12, 2011 at 2:42 PM

Well, I have one more question before I try that.  I needed to limit the angles that the ball would be allowed to go.  So I added this LimitAngles() method, to help ensure that the balls don't bounce completely vertical or horizontal.

I'm wondering if this could be the problem.

/// 
        /// Ensures that the ball only moves in angles.
        /// 
        public void LimitAngles()
        {
            // Limit horizontal movement.
            foreach (Fixture ball in this.balls)
            {
                float yRatio = ball.Body.LinearVelocity.Y / Math.Abs(ball.Body.LinearVelocity.X);
                if (yRatio > 0 && yRatio < (1f / 4f))
                {
                    ball.Body.LinearVelocity = new Vector2(ball.Body.LinearVelocity.X,
                        ball.Body.LinearVelocity.X / 4);
                }
                if (yRatio < 0 && yRatio > -(1f / 4f))
                {
                    ball.Body.LinearVelocity = new Vector2(ball.Body.LinearVelocity.X,
                        -(Math.Abs(ball.Body.LinearVelocity.X / 4)));
                }


                // Limit vertical movement.
                float xRatio = ball.Body.LinearVelocity.X / Math.Abs(ball.Body.LinearVelocity.Y);
                if (xRatio > 0 && xRatio < (1f / 4f))
                {
                    ball.Body.LinearVelocity = new Vector2((ball.Body.LinearVelocity.Y / 4),
                        ball.Body.LinearVelocity.Y);
                }
                if (xRatio < 0 && xRatio > -(1f / 4f))
                {
                    ball.Body.LinearVelocity = new Vector2(-(Math.Abs(ball.Body.LinearVelocity.Y / 4)),
                        ball.Body.LinearVelocity.Y);
                }
            }
        }

 

Maybe, when the ball bounces against the walls, that causes the problems.  This LimitAngles was called in my AfterCollision handler, but this morning I changed it to OnSeparation (it did NOT solve the problem).

If that were the issue, do you know of a better way that I could limit the angles for the ball to be allowed to bounce?

Thanks.


Developer
Apr 12, 2011 at 3:39 PM

Well why don't you remove the angle limit part and see if the wall hugging still happens without it?

Doing angle calculations based on the slope of a vector is generally not a good idea. Try using trigonometric functions if you have to.

float yRatio = ball.Body.LinearVelocity.Y / Math.Abs(ball.Body.LinearVelocity.X);

In this case for instance you are going to divide through zero if LinearVelocity.X is zero. LinearVelocity.X will eventually be zero if your ball hits a wall. Not a good idea...

Furthermore Farseer doesn't like it too much if you fiddle around with its objects manually. So if you have to change an objects direction, try applying a small impulse or force instead of setting the LinearVelocity directly.

Since you mentioned elsewhere you were trying to build something like breakout, why don't you try to set a small gravity in the direction of your paddle. That wouldn't change the trajectory of the balls to much but ensure that they don't bounce indefinitely between two walls. 

Jun 19, 2011 at 3:58 PM
Edited Jun 19, 2011 at 4:01 PM

I've been experiencing the original issue described here whilst running version 3.3.1, having spheres bounce around an enclosed area (using edges, rectangles or 'CreateCompoundPolygon') results in wall hugging in some circumstances. I originaly had this problem on WP7 but have managed to replicate it in the TestBed, the code for this is:

public class SphereEdgeTest : Test
{
    private SphereEdgeTest()
    {
        World.Gravity = Vector2.Zero;

        List<Vertices> borders = new List<Vertices>(4);

        const float borderWidth = 0.1f;
        const float width = 8f;
        const float height = 4.8f;

        //Bottom
        borders.Add(PolygonTools.CreateRectangle(width, borderWidth, new Vector2(0, height), 0));

        //Left
        borders.Add(PolygonTools.CreateRectangle(borderWidth, height, new Vector2(-width, 0), 0));

        //Top
        borders.Add(PolygonTools.CreateRectangle(width, borderWidth, new Vector2(0, -height), 0));

        //Right
        borders.Add(PolygonTools.CreateRectangle(borderWidth, height, new Vector2(width, 0), 0));

        Body body = BodyFactory.CreateCompoundPolygon(World, borders, 1, new Vector2(0, 2.4f));

        foreach (Fixture fixture in body.FixtureList)
        {
            fixture.Restitution = 1f;
            fixture.Friction = 0;
        }

        Body circle = BodyFactory.CreateCircle(World, 1f, 1, new Vector2(1.2f, 2f));
        circle.BodyType = BodyType.Dynamic;
        circle.Restitution = 1f;
        circle.Friction = 0;

        circle.ApplyLinearImpulse(new Vector2(10.9f, 1.25f));
    }

    internal static Test Create()
    {
        return new SphereEdgeTest();
    }
}

I based this code on the 'CirclePenetrationTest' from the TestBed, the major difference here being the scale of the numbers. I'm working with velocity values < 1/10th of the CirclePenetrationTest - I.E. I have:

circle.ApplyLinearImpulse(new Vector2(10.9f, 1.25f));

Where as the original code is:

circle.ApplyLinearImpulse(new Vector2(200, 50));

I don't know if this is related or not but thought I'd mention it. Any suggestions of how to fix this would be greatly appreciated! 


Aug 29, 2013 at 3:59 AM
I am seeing this exact same issue with release 3.5.
I tried disabling the CCD, warm start but it did not solve the problem.
Reducing the VelocityThreshold fixed the immediate problem but started causing weird behaviour in collision response.

Was anybody able to get a solution to this problem ?
Mar 8, 2015 at 8:36 PM
Same intermittent issue ... circle sometimes starts sliding along the wall instead of rebounding/ bouncing off. Anyone found any fix?
Mar 8, 2015 at 10:02 PM
emi_oasis wrote:
Same intermittent issue ... circle sometimes starts sliding along the wall instead of rebounding/ bouncing off. Anyone found any fix?
No. Never found a solution for this. What I eventually did was to handle the collision myself. In the collision callback I handled the collision myself and returned the same value (true or false, I don't exactly remember) to tell the farseer physics that application has handled the collision and it need not to handle it.