Disabling a body does not necessarily stop Narrow Phase collisions

Feb 10, 2009 at 5:21 PM
There seems to be a minor issue with collision handling and disabled bodies. Even if a body is disabled after collision occurs, it will keep colliding if it satisfies narrow phase conditions.

I'm guessing that once a narrow phase collision happens, the bodies are not broad-phase checked again until they fail the narrow phase check. Unfortunately, the "Enabled" check is in the broad phase, so disabling the body doesn't work.

For now, I've worked around the issue by manually moving the body out of collision range when I disable it.
Feb 10, 2009 at 5:29 PM
hmmm. I'm not sure I understand.

Broadphase collision detection happens on each update of the physics engine. If the bodies are able to undergo the broadphase, an arbiter will be created containing the 2 colliding geometries. Then the arbiters gets updated and a narrow phase collision detection occurs. This means that if you disable a body, it will not undergo the broadphase and thus not enter the narrow phase.

Do you have a demo if this? would be great to have a demo with some comments of what happens.
This reminds me to do some checks inside Geom.Collide to make sure that it does not do narrow phase collisions for disabled bodies.
Feb 10, 2009 at 5:42 PM
Thanks for the quick reply, genbox. I don't have an easily isolated example, so I'll try to explain myself more clearly.

I think the issue is the disabled body doesn't get removed from the arbiter list. Since it is still in the arbiter list, it will keep doing narrow phase collision even if it wouldn't be re-added by the broad phase.

From looking at the code, it seems that geoms do not get removed from the arbiter list until they are no longer in contact (in ArbiterList.RemoveContactCountEqualsZero) or is disposed (in ArbiterList.RemoveContainsDisposedBody). I think a check there to also remove geoms when the body longer Enabled (or if the geom is no longer collision-enabled) would solve this particular problem.
Feb 10, 2009 at 5:49 PM
Arh, okay.

So when two geometries collide and you disable their bodies (or if one of them is static) they are still contained within an arbiter because they are still in contact and is not disposed.

Thanks for reporting this ladron. I will fix it in 2.1.
Feb 10, 2009 at 6:35 PM
Cool - thanks!
Feb 10, 2009 at 9:09 PM
I can't seem to replicate this. I've edited the SimpleSamples Demo2 to disable both bodies (also tried with only one of them) when a collision occurs.

The arbiter count stays a 0 as it should. Is there something I'm missing?

Feb 10, 2009 at 9:29 PM
You are correct - it turns out that it is a slightly more complicated edge case. It only happens if the second body is static and does not also get disabled (in my game, the case that causes this is a projectile hitting a wall and being destroyed)

I was able to replicate this behavior with SimpleSamples Demo2. Here is the modified portion:

        public override void LoadContent()

            _rectangleTexture = DrawingHelper.CreateRectangleTexture(ScreenManager.GraphicsDevice, 128, 128, Color.Gold,
            _rectangleOrigin = new Vector2(_rectangleTexture.Width / 2f, _rectangleTexture.Height / 2f);

            _circleTexture = DrawingHelper.CreateCircleTexture(ScreenManager.GraphicsDevice, 64, Color.White,
            _circleOrigin = new Vector2(_circleTexture.Width / 2f, _circleTexture.Height / 2f);

            _rectangleBody = BodyFactory.Instance.CreateRectangleBody(PhysicsSimulator, 128, 128, 1);
            _rectangleBody.Position = new Vector2(256, 384);
            _rectangleGeom = GeomFactory.Instance.CreateRectangleGeom(PhysicsSimulator, _rectangleBody, 128, 128);
            _rectangleGeom.OnCollision = new Geom.CollisionEventHandler(Collision);

            _circleBody = BodyFactory.Instance.CreateCircleBody(PhysicsSimulator, 64, 1);
            _circleBody.IsStatic = true;
            _circleBody.Position = new Vector2(725, 384);
            _circleGeom = GeomFactory.Instance.CreateCircleGeom(PhysicsSimulator, _circleBody, 64, 20);


        bool Collision(Geom geom1, Geom geom2, ContactList contacts)
            geom1.Body.Enabled = false;

            return true;

Feb 10, 2009 at 10:03 PM
Indeed. Now there is an arbiter that should not be there. Thanks for the demo code.