Stopping Collisions

Topics: Developer Forum, Project Management Forum, User Forum
Jul 23, 2009 at 7:46 PM

I have a box that falls onto a IsStatic Platform.  The box bounces around for a while until it settles, however, it never really settles.  The box keeps calling OnCollision and the X and Y continues to change by .001.  How do I get the object to stop bouncing after it settles?

Coordinator
Jul 23, 2009 at 7:50 PM

You can try with the Inactivity Controller. It puts geometries to sleep after a while when they don't move. It requires a lot of tweaking to get just right, but it will improve performance and it will make your geometries stop bouncing.

Just FYI, the bouncing is a part of the engine design. Things never comes completely to rest. They do not in the real world either. Even if geometries are at "rest" (not moving) the OnCollision event still occurs. The geometry is still touching some other geometry.

Jul 23, 2009 at 11:06 PM
Edited Jul 23, 2009 at 11:09 PM

 

What is your opinion on this: http://bishoylabib.blogspot.com/2009/04/how-to-stack-objects-in-farseer-physics.html

Jul 24, 2009 at 2:01 AM

I've managed to get the Inactivity Controller working... somewhat.  It looks like a body retains its forces when becomes idle.  So if there was X Velocity that was below MinimumVelocity and the object becomes active again, it starts moving at X Velocity.

I managed to stop this with FlatRedBall's MethodInstructions :

The concept is that when the OnSeparation event occurs, the object in question registers an instruction (callback) to occur at a specific time.  I have this time set to the MaxIdleTIme of the InactivityController.

blocks[geom2.Id].ObjSprite.Instructions.Clear();
                blocks[geom2.Id].ObjSprite.Instructions.Add(
                    new MethodInstruction<ScreenMain>(
                         this,
                         "ClearIdleForces",
                        new object[] { blocks[geom2.Id] },
                        TimeManager.CurrentTime + myMaxIdleTime / 1000));

Then 'ClearIdleForces' method either clears all forces on the body or re-registers itself at MaxIdleTime - Body.IdleTime :

private void ClearIdleForces(ref PhysicalObject someObject)
         {
            if (someObject.ObjBody.IdleTime >= myMaxIdleTime)
            {
                someObject.ObjBody.ClearForce();
                someObject.ObjBody.ClearTorque();
                someObject.ObjBody.ClearImpulse();
                someObject.ObjBody.LinearVelocity = new Vector2(0, 0);
            }
            else
            {
                someObject.ObjSprite.Instructions.Add(
                    new MethodInstruction<ScreenMain>(
                         this,
                         "ClearIdleForces",
                        new object[] { someObject },
                        TimeManager.CurrentTime + ((myMaxIdleTime - someObject.ObjBody.IdleTime) / 1000)));
            }
        }

 

Jul 24, 2009 at 2:07 AM
Edited Jul 24, 2009 at 2:12 AM

A separate issue I have run into with the Inactivity Ctrlr is setting the ActivationDistance.

ActivationDistance = 6

Player object AutoIdle = False

I have four boxes in a row 5 x 5, player is on the left of the four boxes and the boxes are almost touching.

The distance from the player to the last box on the right is , lets say, 21.

Player object will activate the last box on the right on time, therefore activating two or three boxes and pushing them right through the fourth box.  The fourth box eventually becomes active and goes haywire.

This problem is present in my source @ frbfarseer.codeplex.com

Coordinator
Jul 24, 2009 at 2:18 AM

As I mentioned it requires a lot of tweaking to get just right. The inactivity controller is in no way perfect.

As for the retaining of force. You should only put geometries to rest if they really are at rest. If they have a velocity and they get disabled by the inactivity controller, then they will continue along their path when they wake up. The inactivity controller simply disables bodies when their movement is below a certain level. It is in no way build into the engine, so applyinf force to a sleeping body will not wake it up.

As for the link. One way to increase stacking is to lower the timestep and that is what he did in the link. The engine is an iterative engine and giving it smaller timesteps will increase stability. Another alternative is to increase the iterations of the engine. Stacking is difficult and it also requires a lot of tweaking. All of this will get better in 3.0.

Jul 26, 2009 at 7:43 PM

Looking at InactivityController:

For Each body2 In Me._physicsSimulator.bodyList
                    If ((Not body2.Enabled AndAlso body2.IsAutoIdle) AndAlso Me.IsInActivationDistance(body, body2)) Then
                        body2.Enabled = True
                        body2.IdleTime = 0!
                    End If
                Next

body should wake up body2 if it is within the activation distance.  But this doesn't happen and I'm thinking I need a smaller time step.

If I have 5 inactive blocks in a row and I apply force to the one on the left , block1 wakes up block2, but block2 does not wake up block3.   Why not?

Coordinator
Jul 26, 2009 at 7:46 PM
Edited Jul 26, 2009 at 7:46 PM

Been a long time since I took a look at the controller (it was a user contribution) but I believe it has to move at a higher velocity than the MinimulVelocity given to the controller. block1 wakes up, and it moves so block2 wakes up. But the force applied to block2 is simply too small to move it above the minimum velocity. I think that is what happens. It should at least give you an idea of what happened.

Jul 26, 2009 at 7:57 PM

You're right it was the MinimumVelocity.